API documentation · Podcast endpoints

Podcast transcripts API endpoint

GET /api/v1/podcast-transcripts/ Cursor pagination · newest first

All requests go to https://subalytics.com/api/v1/ with your key in the X-API-key header. Authentication, pagination, date filters and responses & errors apply to every endpoint.

By default returns transcript summaries without speakers or text, which are cheap to page through to find what's new. Add full=true to get the complete transcript.

Query parameters

ParameterTypeDescription
episode_sub_idstringThe transcript of one episode
sub_idstringTranscripts of one podcast
fullstringtrue = include speakers and segments; anything else or omitted = summary only
updated_fromdateLast changed on or after (use for sync)
updated_todateLast changed on or before
limitintResults per page (default 25, max 100). With full=true: default 10, max 10, since a full transcript can be 1–2 MB
cursorstringnext_cursor from the previous page

Response fields

FieldTypeDescription
episode_sub_idstringThe episode this transcript belongs to
podcastobject{sub_id, podcast_name}
episodeobject{episode_sub_id, episode_title, published_at, audio_url, link, image_url}, for convenience; the episodes endpoint is the source of truth. audio_url, link and image_url are always present, null when the feed has none. image_url is the episode's artwork, else the podcast's. audio_url is passed through from the feed as-is and may be a tracking or redirect URL
languagestring | nullLanguage detected from the audio, e.g. en (may differ from the podcast's declared language)
duration_secondsnumber | nullMeasured audio length
speakers_identifiedbooleanfalse = speaker names haven't been identified (yet); labels still work, names are null
created_atdateWhen the transcript was first produced
updated_atdateLast change (re-transcription or speakers identified)
speakersobjectfull=true only. Speaker label → {name, role, title, company}
segmentsarrayfull=true only. {start, end, text, speaker} in order; start/end in seconds from the start of the audio

Speakers

Each segment's speaker (e.g. SPEAKER_00) is a key into speakers. Labels are per transcript: SPEAKER_00 in one episode is unrelated to SPEAKER_00 in another. Identification is automatic and best-effort: any of name, role, title and company may be null. role is the speaker's part in the conversation (host, co-host, guest, …). A segment's speaker may be missing where speakers couldn't be separated.

A transcript can change after it is first published, for example when speaker names are filled in later. Its updated_at changes, so an updated_from sync picks it up again.

Example: one full transcript

GET /api/v1/podcast-transcripts/?episode_sub_id=c41f7a09e2b85d13&full=true
{
  "success": true,
  "results": [
    {
      "episode_sub_id": "c41f7a09e2b85d13",
      "podcast": {
        "sub_id": "a1b2c3d4e5",
        "podcast_name": "Example Business Show"
      },
      "episode": {
        "episode_sub_id": "c41f7a09e2b85d13",
        "episode_title": "Rate Cuts, Robotaxis and the Week in Markets",
        "published_at": "2026-09-24T16:38:09Z",
        "audio_url": "https://media.example.com/c41f7a09e2b85d13.mp3",
        "link": "https://podcasts.example.com/episodes/c41f7a09e2b85d13",
        "image_url": "https://images.example.com/c41f7a09e2b85d13.jpg"
      },
      "language": "en",
      "duration_seconds": 6875.2,
      "speakers_identified": true,
      "speakers": {
        "SPEAKER_00": { "name": "Jane Host", "role": "host", "title": "journalist", "company": "Example Media" },
        "SPEAKER_01": { "name": "Sam Guest", "role": "guest", "title": "economist", "company": null }
      },
      "segments": [
        { "start": 1.0, "end": 9.72, "text": "Welcome back to the show. Big week in markets.", "speaker": "SPEAKER_00" },
        { "start": 10.1, "end": 17.4, "text": "It really was. Let's start with the rate decision.", "speaker": "SPEAKER_01" }
      ],
      "created_at": "2026-09-25T06:12:47Z",
      "updated_at": "2026-09-27T05:48:31Z"
    }
  ],
  "returned_results": 1,
  "limit": 10,
  "next_cursor": null
}

Without full=true, each result has the same fields except speakers and segments.