Base URL and request format
Send requests to https://app.turbocast.io/api/v1. Include your token in the Authorization header:
Authorization: Bearer YOUR_TOKEN
Accept: application/json
Send a Content-Type: application/json header with JSON request bodies. The exceptions are the direct file PUT to a presigned upload URL and artwork uploads, which use multipart/form-data.
Create and protect a token
Create a token after signing in at API tokens. Copy it immediately; the app shows a new token once. You can revoke it from the same page. Treat it as a password and keep it out of browser code, logs, and public repositories.
Tokens belong to a user. A token can list and manage podcasts only in accounts where that user is an admin. Membership without the admin role does not permit publishing.
Every request needs the Authorization: Bearer header. Any other scheme, or a malformed header, receives 401 unauthorized, as does an absent, invalid, or expired token. A valid token without admin permission receives 403 forbidden. A podcast outside the token owner’s accounts receives 404 not_found, so the API does not reveal whether another account’s podcast exists.
Identifiers
Every ID the API returns or accepts is a short string called a hashid, such as r2xupj: podcasts, episodes, channels, and everything else. Use the id values from responses exactly as given, in paths and in request bodies. An ID from one kind of record doesn’t work for another.
A channel’s private token is never used as its API identifier. Always obtain channel IDs from GET /podcasts/:podcast_id/channels.
List available podcasts
curl https://app.turbocast.io/api/v1/podcasts \
-H "Authorization: Bearer $TURBOCAST_TOKEN"
GET /podcasts returns an array of podcasts you administer. GET /podcasts/:id returns one podcast. Each podcast includes:
| Field | Meaning |
|---|---|
id | The podcast hashid used in API paths. |
account_id | The account the podcast belongs to. |
name | The show’s name. |
description | Plain text, or null. |
description_markdown | The description as Markdown, or null when it holds content Markdown can’t express. |
description_editable | Whether description_markdown covers the whole description. |
categories_1 | "Category" or "Category:Subcategory", or null. |
explicit | true or false. |
cover_url | The show’s artwork, or null. |
intro_audio, outro_audio | {url, duration, filename} for the show’s intro and outro clips, or null. |
publishing_mode | channels or legacy. |
time_zone | The time zone used for local-time releases. |
time_zone_confirmed | Whether the time zone has been confirmed. |
needs_public_details | true when the show has a public channel, so directories need a category. |
channels | Active channels as {id, name, channel_type}. Empty for legacy podcasts. |
episodes_count | Number of episodes, including drafts. |
next_episode_number | The highest episode number plus one, starting at 1. |
uses_seasons | Whether any episode has a season number. |
latest_season_number | The most recent episode’s season number, or null. |
imported | Whether the show was imported from another host’s RSS feed. |
import_status | The import’s progress for an imported show. |
is_connected | Whether the show is connected: it stays on its current host and TurboCast syncs its feed. |
origin_feed | The feed a connected show syncs from, or null. |
auto_transcribe | Whether new episodes are transcribed automatically when AI transcription is available. |
created_at | When the podcast was created. |
A publishing_mode of legacy means the podcast has no channel controls in this API. Episode creation, publication, and unpublication still work; sending a channels list when publishing a legacy podcast returns channels_unsupported.