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:

FieldMeaning
idThe podcast hashid used in API paths.
account_idThe account the podcast belongs to.
nameThe show’s name.
descriptionPlain text, or null.
description_markdownThe description as Markdown, or null when it holds content Markdown can’t express.
description_editableWhether description_markdown covers the whole description.
categories_1"Category" or "Category:Subcategory", or null.
explicittrue or false.
cover_urlThe show’s artwork, or null.
intro_audio, outro_audio{url, duration, filename} for the show’s intro and outro clips, or null.
publishing_modechannels or legacy.
time_zoneThe time zone used for local-time releases.
time_zone_confirmedWhether the time zone has been confirmed.
needs_public_detailstrue when the show has a public channel, so directories need a category.
channelsActive channels as {id, name, channel_type}. Empty for legacy podcasts.
episodes_countNumber of episodes, including drafts.
next_episode_numberThe highest episode number plus one, starting at 1.
uses_seasonsWhether any episode has a season number.
latest_season_numberThe most recent episode’s season number, or null.
importedWhether the show was imported from another host’s RSS feed.
import_statusThe import’s progress for an imported show.
is_connectedWhether the show is connected: it stays on its current host and TurboCast syncs its feed.
origin_feedThe feed a connected show syncs from, or null.
auto_transcribeWhether new episodes are transcribed automatically when AI transcription is available.
created_atWhen 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.