---
title: "Start a transcription"
method: POST
path: "/api/v1/transcriptions"
---

# Start a transcription

`POST /api/v1/transcriptions`

## Request

- Base URL: `https://podcaststotext.com`
- URL: `https://podcaststotext.com/api/v1/transcriptions`
- Auth: HTTP bearer

Returns immediately with an id: it does not wait for the transcript. Accepts a direct audio URL or a YouTube, TikTok, Spotify or Apple Podcasts link, which is resolved for you; use /api/v1/podcasts/lookup first only when you need to choose an episode from a show. An accepted request returns 202, a rejected one still answers 4xx, so check `status` rather than the HTTP code: a YouTube video with captions comes back already "completed" and costs nothing. Everything else spends credits.

## Request body

- union
  - object
    - `url` string, required: What to transcribe: a Spotify or Apple Podcasts episode link, a YouTube or TikTok URL, a podcast's RSS feed or episode page (its newest episode for a feed or show page), or a direct audio file. Resolved for you.
    - `audio_url` string: A direct audio file URL you have already resolved yourself. Taken at face value, no lookup, one fewer round trip. Use this or "url".
    - `title` string: Overrides the title resolved from the platform.
    - `language` string: Language hint, e.g. "en". Auto-detected if omitted.
    - `speaker_labels` boolean: Label distinct speakers. Paid plans only; ignored on free.
    - `duration_seconds` number: Only used with a direct audio_url, where the file would otherwise be probed for its length.
  - object
    - `url` string: What to transcribe: a Spotify or Apple Podcasts episode link, a YouTube or TikTok URL, a podcast's RSS feed or episode page (its newest episode for a feed or show page), or a direct audio file. Resolved for you.
    - `audio_url` string, required: A direct audio file URL you have already resolved yourself. Taken at face value, no lookup, one fewer round trip. Use this or "url".
    - `title` string: Overrides the title resolved from the platform.
    - `language` string: Language hint, e.g. "en". Auto-detected if omitted.
    - `speaker_labels` boolean: Label distinct speakers. Paid plans only; ignored on free.
    - `duration_seconds` number: Only used with a direct audio_url, where the file would otherwise be probed for its length.

## Response `202`

Job accepted

- object
  - `id` string
  - `status` 'processing' | 'completed': Already "completed" for caption-sourced videos: do not poll those
  - `source_type` string
  - `message` string
  - `next_actions` string[]

## Other responses

- `400`: Bad input
- `401`: Missing or invalid API key
- `402`: Account is out of credits
- `403`: The account's plan does not allow this: either it includes no API access, or the requested scope needs write access. `error.code` is "plan_required". No plan is in that state today, so in practice you will see 402 insufficient_credits instead, which means the plan is fine and the balance is empty.
- `422`: The source has no transcribable audio (error.code "source_unavailable")
- `429`: Too many requests. Limits are per API key, counted per minute and per day, and depend on the plan. Operations that cost money to run (transcription, renders, AI) carry a second, tighter limit of their own. Read RateLimit-Remaining on every successful response to pace requests rather than waiting to be refused.
- `502`: The media could not be fetched; often transient (error.code "source_unavailable")
- `503`: Credit-spending operations are paused system-wide for the rest of the day while unusual load is investigated. `error.code` is "service_unavailable". This is NOT a limit on the calling account, and upgrading does not lift it. Honour Retry-After. It is deliberately not a 429 so a client cannot mistake it for its own budget.

---

[API](https://skmtc.dev/podcaststotext/apis/podcaststotext-api.md) · [All operations](https://skmtc.dev/podcaststotext/apis/podcaststotext-api/llms.txt) · [OpenAPI document](https://skmtc.dev/podcaststotext/apis/podcaststotext-api/revisions/ef711acf4bc3?raw)
