DocsErrors
Errors
The error envelope, every error code, and which ones to retry.
A request error means the API refused the call. A job failure means the API accepted the transcription, but it later ended with status set to failed.
The error envelope
Every /v1 request error has the same shape:
{
"error": {
"code": "insufficient_minutes",
"message": "Not enough minutes",
"retryable": false,
"action_url": "https://transcript1.com/dashboard/billing",
"minutes_needed": 20,
"minutes_remaining": 3
}
}Handle errors by code. Display message to the user; its wording may change. When retryable is true, the same request may succeed later.
Some errors add fields next to retryable:
| Field | On which errors | Meaning |
|---|---|---|
action_url | insufficient_minutes, no_active_plan, topup_needs_user | Where to buy a plan or a top-up. |
minutes_needed, minutes_remaining | insufficient_minutes | Minutes the request needs (null when it is not known yet) and minutes you have. |
reason, packs | topup_needs_user | Why the card was not charged, and the packs that were requested. |
supported_platforms | unsupported_platform | The platforms you can send: ["youtube", "x", "tiktok", "instagram", "facebook", "bluesky", "twitch", "dailymotion", "pinterest", "linkedin", "snapchat"]. |
missing_chunks | upload_incomplete | Indexes of the chunks that did not arrive. |
max_bytes | media_too_large | The largest file size allowed for you, in bytes. |
params | invalid_request | For body and query validation errors, an object mapping each field to what is wrong with it. |
Request errors
| HTTP status | code | Retryable | When |
|---|---|---|---|
| 400, 422 | invalid_request | No | A parameter or body field is missing or invalid, for example diarize together with source: "captions", or reuse_recent with webhook_url. Also returned when the request body is not valid JSON. |
| 422 | invalid_url | No | Use a YouTube, X, TikTok, Instagram, Facebook or Bluesky link, or another platform listed in Sources and options. Also returned when platform does not match the link. |
| 422 | unsupported_platform | No | platform is not supported. |
| 422 | unsupported_media | No | The uploaded file does not have a supported extension. |
| 401 | unauthorized | No | The credential is missing, invalid, expired or revoked, or the upload token is invalid or expired. |
| 403 | insufficient_scope | No | An OAuth token lacks transcriptions:read or transcriptions:write. |
| 403 | email_not_verified | No | Verify your email address before creating transcriptions or live sessions. |
| 402 | insufficient_minutes | No | Your usable minutes are 0 or fewer than the transcription needs, or fewer than one started minute of a live session. When auto top-up is on, transcript1 tries to top up first. Buy minutes at action_url, or let an agent buy them with POST /v1/topups or the MCP tool top_up. |
| 402 | no_active_plan | No | You tried to buy a top-up without an active paid plan. POST /v1/topups and the dashboard's billing endpoints return this, not the transcription endpoints. |
| 402 | topup_needs_user | Only for pending and in_progress | POST /v1/topups did not charge the card. reason says why: not_allowed (the credential cannot buy top-ups, or its user is not a team admin), cap_reached (the monthly agent limit has no room), card_declined, authentication_required or no_card. The user can buy the packs at action_url. For pending (the payment is not confirmed yet) and in_progress (another top-up is running), the charge may still complete: retry later with the same Idempotency-Key instead of sending the user to buy. |
| 404 | not_found | No | The transcription does not exist or belongs to another team. |
| 409 | upload_incomplete | No | Some chunks are missing. Send them and complete again. |
| 409 | invalid_state | No | The transcription is not awaiting an upload, so chunks can no longer be sent or completed. |
| 409 | session_ended | No | A live session has ended, so POST /v1/live/sessions/:id/token cannot issue a token. Also sent as a WebSocket error event. |
| 422 | unsupported_language | No | The language of a live session is not supported. |
| 422 | unsupported_translation | No | The translate_to language of a live session is not supported, or live translation is not available. |
| 409 | idempotency_conflict | No | The Idempotency-Key was already used with different parameters. |
| 413 | media_too_large | No | The file is larger than your limit. See Uploads. |
| 413 | invalid_request | No | A JSON body over 1 MB. Files use media_too_large instead. |
| 429 | rate_limited | Yes | Too many requests per minute. Wait for Retry-After seconds. |
| 429 | too_many_active_jobs | Yes | Too many transcriptions running, or too many open uploads. Wait for Retry-After seconds. |
| 429 | too_many_live_sessions | Yes | Your plan's simultaneous live sessions are in use. Wait for Retry-After seconds (30). |
| 500 | internal_error | Yes | Something went wrong on our side. Retry shortly. |
| 503 | service_unavailable | Yes | transcript1 is temporarily unavailable. Retry shortly. |
| 503 | live_capacity | Yes | All live capacity is in use. Wait for Retry-After seconds (30) and create the session again. |
| 503 | live_unavailable | No | Live transcription is not available right now. |
Requests from a browser that use a login cookie instead of a bearer credential are also checked for their origin. A request from another site returns 403 forbidden_origin. API calls with an Authorization header are not affected.
Every 429 response includes a Retry-After header with the number of seconds to wait. See Billing and limits for the limits themselves.
Retry a request
- Retry only when
retryableistrue:rate_limited,too_many_active_jobs,too_many_live_sessions,live_capacity,internal_error,service_unavailable, andtopup_needs_userwithreasonpendingorin_progress. HonorRetry-Afterwhen it is present and back off between attempts otherwise. - When retrying
POST /v1/transcriptionsorPOST /v1/topups, send the sameIdempotency-Keyheader to avoid a second charge if the original request succeeded. - Fix the request before sending it again for every other code.
Live transcription
POST /v1/live/sessions and the other live endpoints use the same envelope. invalid_request, unsupported_language, insufficient_minutes and email_not_verified apply to them as well, together with the live codes in the table above. Creating a session is not idempotent, so a retry after too_many_live_sessions or live_capacity creates a new session.
After the session exists, problems arrive on the WebSocket as error events and close codes, not as HTTP errors. See Live transcription for every event.
| Close code | Meaning |
|---|---|
1000 | Normal close, after session.ended. |
1011 | Unexpected server error. Resume with a new token. |
1012 | Server restart, after reconnect. Resume with a new token. |
4001 | Invalid, expired or already used token. |
4004 | Session not found or already ended. |
4008 | Protocol violation: an odd-length or oversized audio frame. |
4010 | Replaced by a newer connection to the same session. |
A live session that ends for a reason such as balance_exhausted or idle_timeout is not an error: it sends session.ended with an end reason and is saved. See End reasons.
Job failures
When a transcription ends with status set to failed, the object has error: { "code", "message" }. Failures can happen after the request returned, so read error when you poll or in the transcription.failed webhook. A failed translation sends a transcription.translation.failed webhook and never fails the transcript.
error.code | Meaning | Try again? |
|---|---|---|
media_unavailable | The video does not exist or is no longer available. | No. Check the URL. |
media_private | The video is private. | No. Use a public post or a public or unlisted YouTube video. |
login_required | The platform requires a logged-in account. | No. Permanent failure; not retried. |
no_audio | The video has no sound track. | No. Permanent failure; not retried. |
age_restricted | The video is age-restricted. | No. Upload the file instead. |
live_stream | The video is a live stream, or a stream that has not started yet. | After the stream has ended. |
no_captions | source was captions and the video has no usable caption track. | Use source: "auto" or "stt". |
media_too_long | Speech-to-text accepts up to 5 hours of media. | No. Split the media. |
unsupported_media | The file could not be read or has no audio track. | No. Send a supported file. |
no_speech | No speech was detected. | No. |
unsupported_language | The language of this media is not supported. | No. Set language to a supported code or "auto". |
insufficient_minutes | Your minutes ran out before the transcription could be charged, and auto top-up, if on, could not add more. | After you top up. |
fetch_failed | Fetching the media failed after several attempts. | Yes, later. |
transcription_failed | Speech-to-text failed after several attempts. | Yes, later. |
Failed and canceled transcriptions are never charged. Minutes that were taken for a transcription are returned when it fails or is canceled.
Updated November 5, 2026