DocumentazioneEndpoint API
Endpoint API
Consulta parametri ed esempi per tutti gli endpoint /v1, oppure scarica la specifica OpenAPI in formato JSON o YAML.
Introduzione
https://api.transcript1.com/v1Usa https://api.transcript1.com/v1 come URL di base per le chiamate API.
- Invia e ricevi body JSON. I nomi dei campi usano
snake_case. - Le date seguono ISO 8601 in UTC, ad esempio
2026-10-13T09:30:00.000Z. - Durata e tempi della trascrizione sono espressi in secondi.
- Per interpretare gli errori, fai riferimento alla struttura comune.
- Nelle risposte alle chiamate autenticate trovi sempre
X-RateLimit-LimiteX-RateLimit-Remaining. I dettagli sono in Costi e limiti. - Con
source=autocerchiamo prima sottotitoli adatti nella lingua originale su YouTube, X, TikTok, Bluesky, Dailymotion e LinkedIn. Se non possiamo usarli, passiamo allo speech-to-text. Non tutti i video hanno sottotitoli. Consource=captionsattivi la modalitàcaptions(solo sottotitoli): non scarichiamo audio e non avviamo STT. Senza una traccia adatta ricevino_captions. Consource=stto il riconoscimento dei parlanti, usiamo direttamente l'audio. Consulta Link e opzioni di trascrizione per le restrizioni e per sapere quando ricevi timestamp dei segmenti o delle parole.
Puoi scaricare la specifica OpenAPI per usarla nei tuoi strumenti:
Autenticazione
curl https://api.transcript1.com/v1/account \
-H "Authorization: Bearer $TRANSCRIPT1_API_KEY"Per autenticarti, aggiungi l'header Authorization nel formato Authorization: Bearer <token>.
- Puoi usare una chiave API, riconoscibile dal prefisso
t1_. La crei in “API keys” e puoi usarla con tutti gli endpoint. - I client MCP come Claude e ChatGPT ricevono un access token OAuth quando li colleghi. Il prefisso è
t1o_e gli scope sonotranscriptions:readetranscriptions:write.
| Scope | Chiamate consentite |
|---|---|
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 al token manca lo scope necessario, l'API risponde
403 insufficient_scope. - Se non invii una credenziale o non è valida, ricevi
401 unauthorized.
Per inviare i chunk con PUT /v1/transcriptions/:id/upload/chunks/:index, usa invece X-Upload-Token. Lo ricevi all'apertura del caricamento. Segui la procedura in Caricare file.
Idempotenza
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"}'Quando chiami POST /v1/transcriptions, aggiungi Idempotency-Key: potrai ripetere la chiamata senza creare una seconda trascrizione.
Scegli un valore da 1 a 255 caratteri e invialo nell'header, non nella query.
- Se riusi chiave e parametri, recuperi la trascrizione della prima chiamata e non paghi di nuovo.
- Se riusi la chiave ma cambi i parametri, ricevi
409 idempotency_conflict. - Per un caricamento in parti, ripetere la chiamata di creazione con la stessa chiave ti dà un nuovo token di caricamento.
Errori
{
"error": {
"code": "insufficient_minutes",
"message": "Not enough minutes",
"retryable": false,
"action_url": "https://transcript1.com/dashboard/billing",
"minutes_needed": 20,
"minutes_remaining": 3
}
}- Se l'API rifiuta la chiamata, ricevi l'errore subito nella risposta.
- Se la chiamata viene accettata ma la trascrizione non riesce durante l'elaborazione, il suo
statusdiventafailed.
Come leggere un errore API
Quando una chiamata /v1 non viene accettata, trovi un oggetto error con code, message e retryable.
- Nel tuo codice, distingui i casi usando
code. - Usa
messageper mostrare la spiegazione all'utente, senza basare la logica sul testo: può cambiare. - Con
retryableuguale atrue, puoi riprovare la stessa chiamata più tardi.
In alcuni casi trovi altri campi oltre a retryable:
| Campo | Codice associato | A cosa serve |
|---|---|---|
action_url | insufficient_minutes | Link per acquistare un piano o aggiungere minuti con una ricarica. |
minutes_needed, minutes_remaining | insufficient_minutes | Minuti necessari per la chiamata e saldo disponibile. I minuti necessari valgono null se non li conosciamo ancora. |
supported_platforms | unsupported_platform | Elenco delle piattaforme accettate: ["youtube", "x", "tiktok", "instagram", "facebook", "bluesky", "twitch", "dailymotion", "pinterest", "linkedin", "snapchat"]. |
missing_chunks | upload_incomplete | Indici delle parti del file che devi ancora inviare. |
max_bytes | media_too_large | Limite di dimensione del file per il tuo account, in byte. |
params | invalid_request | Negli errori di validazione del body o della query, associa ogni campo alla spiegazione del problema. |
Quando l'API rifiuta la chiamata
| Stato HTTP | code | Puoi riprovare senza modifiche? | Causa |
|---|---|---|---|
| 400, 422 | invalid_request | No | Manca un parametro o un campo del body, oppure il valore non è valido. Succede anche con diarize insieme a source: "captions", con reuse_recent insieme a webhook_url o con un body che non contiene JSON valido. |
| 422 | invalid_url | No | Il link non è valido oppure platform non corrisponde al link. Usa YouTube, X, TikTok, Instagram, Facebook, Bluesky o una delle altre piattaforme in Link e opzioni di trascrizione. |
| 422 | unsupported_platform | No | Il valore di platform non rientra tra quelli accettati. |
| 422 | unsupported_media | No | L'estensione del file non è tra quelle supportate. |
| 401 | unauthorized | No | Manca la credenziale, oppure non è valida, è scaduta o è stata revocata. Vale anche per un token di caricamento non valido o scaduto. |
| 403 | insufficient_scope | No | Il token OAuth non ha lo scope transcriptions:read o transcriptions:write necessario per la chiamata. |
| 403 | email_not_verified | No | Devi confermare l'indirizzo email prima di avviare una trascrizione. |
| 402 | insufficient_minutes | No | Hai 0 minuti utilizzabili, oppure non bastano per questa trascrizione. |
| 402 | no_active_plan | No | Per acquistare una ricarica serve un piano a pagamento attivo. Questo errore arriva dall'endpoint di fatturazione della dashboard, non dagli endpoint di trascrizione. |
| 404 | not_found | No | Nessuna trascrizione corrisponde all'ID, oppure appartiene a un altro team. |
| 409 | upload_incomplete | No | Il file non è completo: invia i chunk mancanti e richiama il completamento. |
| 409 | invalid_state | No | La trascrizione non è più in attesa del file. Non puoi inviare altri chunk né completare il caricamento. |
| 409 | idempotency_conflict | No | Hai già usato Idempotency-Key con parametri diversi. |
| 413 | media_too_large | No | La dimensione del file supera il limite del tuo account. Consulta Caricare file. |
| 413 | invalid_request | No | Il body JSON supera 1 MB. Per i file, il codice corrispondente è media_too_large. |
| 429 | rate_limited | Sì | Hai superato il numero di chiamate al minuto. Aspetta quanto indicato da Retry-After, in secondi. |
| 429 | too_many_active_jobs | Sì | Hai troppe trascrizioni in corso o troppi caricamenti aperti. Aspetta quanto indicato da Retry-After, in secondi. |
| 500 | internal_error | Sì | Si è verificato un errore nei nostri sistemi. Puoi riprovare tra poco. |
| 503 | service_unavailable | Sì | Il servizio non è disponibile al momento. Puoi riprovare tra poco. |
Se il browser si autentica con un cookie di login, controlliamo anche l'origine della chiamata. Da un altro sito ricevi 403 forbidden_origin.
Il controllo non si applica alle chiamate API con l'header Authorization.
In tutte le risposte 429, l'header Retry-After indica quanti secondi aspettare. Trovi le soglie per piano in Costi e limiti.
Quando e come riprovare
- Ripeti la chiamata senza modificarla solo con
retryableuguale atrue: vale perrate_limited,too_many_active_jobs,internal_erroreservice_unavailable. - Aspetta i secondi di
Retry-After, se presente. Altrimenti aumenta l'intervallo tra i tentativi. - Per ripetere
POST /v1/transcriptions, mantieni lo stessoIdempotency-Key. Se la prima chiamata era riuscita, eviti un secondo addebito. - Con gli altri codici, risolvi prima il problema della chiamata.
Quando la trascrizione non riesce
Se una trascrizione ha status uguale a failed, trovi il motivo nell'oggetto error, con i campi code e message.
Può succedere anche dopo la risposta alla chiamata iniziale. Controlla error quando leggi lo stato o ricevi il webhook transcription.failed.
error.code | Cosa è successo | Cosa fare |
|---|---|---|
media_unavailable | Il video non esiste oppure non è più accessibile. | Non riprovare lo stesso link: controlla l'URL. |
media_private | Non possiamo accedere al video perché è privato. | Usa un post pubblico o un video YouTube pubblico o non in elenco. |
login_required | Per vedere il video serve il login sulla piattaforma. | Non riproviamo: è un errore permanente. |
no_audio | Manca la traccia audio del video. | Non riproviamo: è un errore permanente. |
age_restricted | La piattaforma applica un limite di età al video. | Non riprovare il link; carica il file. |
live_stream | La diretta è in corso o deve ancora iniziare. | Aspetta che sia finita, poi riprova. |
no_captions | Hai scelto source uguale a captions, ma manca una traccia di sottotitoli adatta. | Passa a source: "auto" o "stt". |
media_too_long | La registrazione supera il limite di 5 ore per lo speech-to-text. | Dividila in parti più brevi prima di inviarla. |
unsupported_media | Non riusciamo a leggere il file, oppure manca la traccia audio. | Invia un file in un formato supportato. |
no_speech | Nessun parlato rilevato. | Non riprovare la stessa registrazione. |
unsupported_language | Non supportiamo la lingua della registrazione. | Correggi language con un codice supportato oppure "auto". |
insufficient_minutes | Al momento dell'addebito non avevi più abbastanza minuti. | Fai una ricarica, poi riprova. |
fetch_failed | Non siamo riusciti a scaricare la registrazione dopo più tentativi. | Puoi riprovare più tardi. |
transcription_failed | La trascrizione dell'audio non è riuscita dopo più tentativi. | Puoi riprovare più tardi. |
Se la trascrizione non riesce o la annulli, non paghi. Se avevamo già scalato dei minuti, li restituiamo al tuo saldo.
L’oggetto 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."
}
]
}
}Campi
- idstringobbligatorio
- objectstringobbligatorio
Valori accettati
transcription - statusstringobbligatorio
Valori accettati
awaiting_uploadqueuedfetchingtranscribingcompletedfailedcanceled - sourceobjectobbligatorio
Mostra i campi annidatiNascondi i campi annidati
With
url- platformstringobbligatorio
- urlstringobbligatorioammette null
- media_idstringobbligatorioammette null
With
filename- platformstringobbligatorio
Valori accettati
upload - filenamestringobbligatorioammette null
- sizenumberobbligatorioammette null
- mediaobjectobbligatorioammette null
Mostra i campi annidatiNascondi i campi annidati
- titlestringfacoltativoammette null
- authorstringfacoltativoammette null
- author_urlstringfacoltativoammette null
- thumbnail_urlstringfacoltativoammette null
- filenamestringfacoltativo
- mime_typestringfacoltativo
- sizenumberfacoltativo
- duration_secondsnumberfacoltativoammette null
- optionsobjectobbligatorio
Mostra i campi annidatiNascondi i campi annidati
- sourcestringobbligatorio
Valori accettati
autocaptionsstt - languagestringobbligatorio
- diarizebooleanobbligatorio
- transcript_sourcestringobbligatorioammette null
Valori accettati
youtube_captionsx_captionsspeech_to_text - caption_kindstringobbligatorioammette null
Valori accettati
manualauto_generated - languagestringobbligatorioammette null
- billed_minutesintegerobbligatorioammette null
- cachedbooleanobbligatorio
- errorobjectobbligatorioammette null
Mostra i campi annidatiNascondi i campi annidati
- codestringobbligatorio
- messagestringobbligatorioammette null
- created_atstring · date-timeobbligatorioammette null
- completed_atstring · date-timeobbligatorioammette null
- deleted_atstring · date-timeobbligatorioammette null
When the transcription was deleted. Always
nullunless the request includesinclude_deleted=true. - transcriptobjectfacoltativo
Included in
GETresponses for completed transcriptions.Mostra i campi annidatiNascondi i campi annidati
- textstringobbligatorio
- speakersarray of stringsobbligatorio
- segmentsarray of objectsobbligatorio
Mostra i campi annidatiNascondi i campi annidati
- startnumberobbligatorio
- endnumberobbligatorio
- speakerstringobbligatorioammette null
- languagestringobbligatorioammette null
- textstringobbligatorio
- wordsarray of objectsfacoltativoammette null
Mostra i campi annidatiNascondi i campi annidati
- startnumberobbligatorio
- endnumberobbligatorio
- textstringobbligatorio
- confidencenumberfacoltativoammette null
- speakerstringobbligatorioammette 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
- waitintegerfacoltativoammette nullValore predefinito: 0
Seconds to wait for a final status before responding, up to 60. Defaults to 0.
- reuse_recentstringfacoltativoValore predefinito: 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.Valori accettati
truefalse
Headers
- Idempotency-Keystringfacoltativo
Returns the original transcription when you repeat a request with the same key and parameters.
Body
With url
- platformstringfacoltativo
Optional; detected from the link. If supplied, must match the link.
Valori accettati
youtubextiktokinstagramfacebookblueskytwitchdailymotionpinterestlinkedinsnapchat - urlstringobbligatorio
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.
- sourcestringfacoltativo
"auto" uses YouTube or X captions when available, otherwise speech-to-text. "captions" is YouTube/X-only. "stt" always uses speech-to-text.
Valori accettati
autocaptionsstt - languagestringfacoltativo
- diarizebooleanfacoltativo
- webhook_urlstring · urifacoltativo
With upload
- uploadobjectobbligatorio
Mostra i campi annidatiNascondi i campi annidati
- filenamestringobbligatorio
- sizeintegerobbligatorio
- mime_typestringfacoltativo
- sourcestringfacoltativo
Valori accettati
autostt - languagestringfacoltativo
- diarizebooleanfacoltativo
- webhook_urlstring · urifacoltativo
multipart/form-data
- filestring · binaryobbligatorio
- sourcestringfacoltativo
Valori accettati
autostt - languagestringfacoltativo
- diarizebooleanfacoltativo
- webhook_urlstring · urifacoltativo
Risposta
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
Altri codici di stato
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
- idstringobbligatorio
Query
- waitintegerfacoltativoammette nullValore predefinito: 0
Seconds to wait for a final status before responding, up to 60. Defaults to 0.
- formatstringfacoltativoValore predefinito: json
Valori accettati
jsontextsrtvtt - includestringfacoltativo
Valori accettati
words - timestampsstringfacoltativoValore predefinito: false
Valori accettati
truefalse - include_deletedstringfacoltativoValore predefinito: false
Also returns deleted transcriptions as read-only records without a transcript. Their
deleted_atis set. Defaults tofalse.Valori accettati
truefalse
Risposta
200 OK— The transcription, or the rendered transcript202 Accepted— A rendered format was requested while the transcription is still processing
Altri codici di stato
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
- limitintegerfacoltativoValore predefinito: 20
- cursorstringfacoltativo
- statusstringfacoltativo
Valori accettati
awaiting_uploadqueuedfetchingtranscribingcompletedfailedcanceled - platformstringfacoltativo
- include_deletedstringfacoltativoValore predefinito: false
Also returns deleted transcriptions as read-only records without a transcript. Their
deleted_atis set. Defaults tofalse.Valori accettati
truefalse
Risposta
200 OK— A page of transcriptions
Altri codici di stato
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"La risposta non contiene un body
Path
- idstringobbligatorio
Risposta
204 No Content— Canceled or deleted
Altri codici di stato
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
- idstringobbligatorio
- indexintegerfacoltativoammette null
Zero-based chunk number from the upload plan
Headers
- X-Upload-Tokenstringobbligatorio
Body
- (body originale)string · binaryobbligatorio
Risposta
200 OK— The chunk was stored
Altri codici di stato
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
- idstringobbligatorio
Risposta
200 OK— Upload progress
Altri codici di stato
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
- idstringobbligatorio
Risposta
202 Accepted— The transcription is queued
Altri codici di stato
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
}
}Risposta
200 OK— The authenticated user's account
Altri codici di stato
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.
L’oggetto 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
}
}Campi
- objectstringobbligatorio
Valori accettati
account - userobjectobbligatorio
Mostra i campi annidatiNascondi i campi annidati
- idstringobbligatorio
- emailstringobbligatorio
- planobjectobbligatorioammette null
Mostra i campi annidatiNascondi i campi annidati
- idstringobbligatorio
- namestringobbligatorio
- minutesobjectobbligatorio
Mostra i campi annidatiNascondi i campi annidati
- remainingnumberobbligatorio
- cyclenumberobbligatorio
- topupnumberobbligatorio
- topup_usablebooleanobbligatorio
- resets_atstring · date-timeobbligatorioammette null
- renews_atstring · date-timeobbligatorioammette null
- limitsobjectobbligatorio
Mostra i campi annidatiNascondi i campi annidati
- requests_per_minutenumberobbligatorio
- max_active_jobsnumberobbligatorio
Webhook
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
}
}Specifica webhook_url alla creazione per ricevere una notifica: transcript1 invia un POST firmato a quell'indirizzo quando il testo è pronto o la trascrizione non riesce.
Puoi configurare i webhook solo nell'API REST. Il server MCP non accetta un parametro per attivarli.
Scegliere l'URL che riceve le notifiche
In POST /v1/transcriptions, aggiungi webhook_url:
- Nel body JSON, se passi un link video supportato o apri un caricamento in parti.
- Nei campi del form, se carichi il file intero in una sola chiamata.
Controlla che l'URL:
- Usi HTTPS.
- Non includa nome utente o password.
- Risolva a un indirizzo pubblico.
Con indirizzi privati, di loopback, link-local o comunque non pubblici, ricevi 422 invalid_request. Verifichiamo l'indirizzo sia alla creazione della trascrizione sia a ogni invio del webhook.
Non puoi usare webhook_url insieme a reuse_recent=true.
Quali eventi ricevi
type | Quando lo inviamo |
|---|---|
transcription.completed | Lo stato passa a completed. |
transcription.failed | Lo stato passa a failed. Trovi code e message in data.error. |
Se annulli una trascrizione, non inviamo webhook.
Cosa contiene la notifica
Nel body JSON trovi:
created_at, la data di creazione dell'evento.data, l'oggetto trascrizione senza il campotranscript.
Per ottenere il testo, usa l'id presente in data e chiama GET /v1/transcriptions/:id.
La chiamata ha questi header:
Content-Type: application/jsonUser-Agent: transcript1-webhooks/1.0X-Transcript1-Signature, per verificare la firma come spiegato qui sotto.
Controllare la firma prima di usare i dati
Leggi l'header X-Transcript1-Signature, presente a ogni invio nel formato t=<unix seconds>,v1=<hex digest>.
tindica il momento della firma, come timestamp Unix in secondi.- Per ottenere
v1, calcola l'HMAC-SHA256 di"<t>.<raw body>"e codificalo in esadecimale. Unisci il valore dit, un punto e il body esattamente come lo hai ricevuto. Come chiave usa tutto il segreto di firma, inclusowhsec_.
Controlla la firma sui byte originali del body, prima del parsing JSON. Se fai il parsing e poi serializzi di nuovo, potresti cambiare spazi o ordine delle chiavi: la firma non corrisponderebbe più.
- Per confrontare le firme, usa un confronto in tempo costante.
- Scarta le chiamate con un
ttroppo distante dall'ora corrente. Negli esempi la tolleranza è di 5 minuti. - In Express, acquisisci il body come testo prima di fare il parsing.
- In Flask, usa
request.get_data(as_text=True)per fornire il valore diraw_body.
Gestire il segreto di firma
Ogni team ha un segreto con prefisso whsec_, usato per firmare i webhook di tutte le sue trascrizioni.
Puoi visualizzarlo o sostituirlo in “Webhooks”.
La sostituzione è immediata: da quel momento firmiamo i webhook con il nuovo segreto.
Risposte, nuovi tentativi e duplicati
- Rispondi con un codice
2xxper confermare la ricezione. - Consideriamo il tentativo non riuscito se riceviamo un altro codice, incontriamo un errore di connessione o non otteniamo risposta entro 10 secondi.
- In quel caso riproviamo, fino a 6 tentativi totali, con backoff esponenziale: aspettiamo 2, 4, 8, 16 e 32 minuti tra un invio e l'altro. L'ultimo arriva circa un'ora dopo il primo.
- Indica direttamente l'URL finale: transcript1 non segue i redirect e considera una risposta
3xxun tentativo non riuscito. - Lo stesso evento può arrivare più volte, ad esempio se il tuo server risponde dopo il timeout. Riconosci i duplicati dalla coppia
data.idetypee ignorali.