PodcastsToText
Reference

Error codes

Every code the API returns, what causes it, and whether retrying will help.

Every error has the same shape, whatever went wrong.

The envelope
{
  "error": {
    "code": "insufficient_scope",
    "message": "This key does not have the \"transcriptions:write\" scope.",
    "how_to_fix": "Create a new key with the \"transcriptions:write\" scope at https://podcaststotext.com/dashboard/api-keys."
  }
}
FieldWhat it is for
codeStable and machine-readable. Branch on this, never on the message.
messageWhat went wrong, for a human reading a log.
how_to_fixWhat to do about it. Always present: read it before retrying anything.

Every code

StatusCodeCauseRetry?
400bad_requestMalformed JSON, a missing required field, or a URL that is neither media nor a recognised platform. Also a time-coded export of a transcript with no timings.No, fix the request
401unauthorizedMissing, unknown, revoked or expired key. All four are reported identically.No, fix the key
402insufficient_creditsThe balance is below what the episode needs.After topping up
403insufficient_scopeThe key is valid but lacks a scope this endpoint requires.No, mint a new key
403plan_requiredThe plan has no API access, or the operation needs write access.After changing plan
404not_foundNo such id, or it belongs to another account. Deliberately indistinguishable.No
422source_unavailableThe platform could not give us usable audio, most often a YouTube video with no caption track.No, the source will not change
429rate_limitedPer-minute, per-day or per-operation limit.Yes, after Retry-After
429too_many_in_flightAt the plan’s concurrency cap for transcriptions.Yes, once one of yours finishes
429ai_daily_limit_reachedThe account has used its daily AI fair-use allowance. Counts new generations only, fetching a cached one is free and unmetered. Per ACCOUNT, not per key.Yes, after Retry-After, which is the reset
403ai_operation_too_largeThe transcript is long enough that this one operation needs more AI units than the plan allows in a whole day. Distinct from the 429 above: the allowance is not spent, it is too small for this episode.No, waiting does not help. Upgrade, or use a shorter episode
429ai_rate_limitedToo many AI generations in one minute. Usually something regenerating in a loop.Yes, after Retry-After
403ai_pass_budget_reachedThe episode was paid for with a one-time pass, and the fixed AI budget that pass carries for it is spent. Lifetime, not daily: a pass is bought once, so nothing resets. Anything already generated stays readable.No, a plan carries a daily allowance
403translation_limit_reachedThis transcript already holds as many distinct languages as the plan allows. Not plan_required, the plan does include translation.No, reuse a language, or force
500internal_errorOur fault.Yes, after a few seconds
variestranscription_failedThe job could not be created. The status carries the reason: 400 unreachable audio, 413 a file over the plan’s upload cap, 422 a host that refused us, 500/502 our side or the speech service.Only on 5xx
502source_unavailableWe could not fetch the media. For TikTok this is usually the extraction worker being busy or slow rather than anything about the link.Sometimes, see below
502ai_unavailableShow notes, chapters or translation failed upstream. A model provider being degraded, not a bad request.Yes, after a few seconds
503service_unavailableCredit-spending operations are paused system-wide for the rest of the day. Not a limit on your account.Yes, after Retry-After

503 is ours, not yours. We have paused every credit-spending operation across all accounts. Upgrading will not lift it and neither will slowing down. Honour Retry-After. Deliberately not a 429, so it cannot be mistaken for your own budget.

Not every 402 is about credits. Two plan limits arrive as 402 rather than 403: an episode over the free plan’s 30-minute cap, and a paid-only format. Topping up clears neither: read message, not just code.

The two 429s are not the same

The distinction most worth encoding in your client.

`rate_limited``too_many_in_flight`
MeansYou are calling too fastYou have too many transcriptions running
Fixed byWaiting, then slowing downOne of *your* jobs finishing
Exponential backoffCorrectPointless on its own
Right responseHonour Retry-AfterPoll ?status=processing, start one as each completes

Retrying well

  • Retry 429, 500 and network failures. Nothing else: a 400 will fail identically forever.
  • Honour Retry-After when it is present; it is not a suggestion.
  • Exponential backoff with jitter after that. Without jitter, everything you deprived of a slot retries in lockstep.
  • Cap total attempts. An unbounded retry loop against a permanent error is how an incident becomes an outage.
  • Retry 503 too, it is a system-wide pause, not your account, and Retry-After says when it lifts.
  • POST /api/v1/transcriptions is not idempotent: a retry after an unclear failure can start a second transcription and spend credits twice. Check ?status=processing before retrying a create.

source_unavailable, in detail

PlatformStatusWhyWhat to do
YouTube422No caption track, we never download audio.Use a video with captions, or pass the audio as audio_url.
TikTok502The extraction worker was at capacity, or the download outran the request budget.Retry once. If it keeps failing the video is private, removed or region-locked. Pass the audio as audio_url.
Spotify422Spotify Originals and Exclusives have no public RSS feed, and a deleted or region-locked episode has no fetchable audio.Try another episode from the show, or pass a direct .mp3 as audio_url.
Apple Podcasts422The episode parsed, but its feed no longer offers that enclosure.Try another episode, or pass the audio directly.

A 500 carries no detail on purpose: error text is a place internals leak. Retry after a few seconds; if it persists, mail support@podcaststotext.com with the endpoint, the approximate time, and the id if you have one.