# Podcast transcripts API endpoint

Source: https://subalytics.com/docs/podcast-transcripts/

> GET /api/v1/podcast-transcripts/: timestamped podcast transcripts with identified speakers. Parameters, response fields and a full example.

`GET /api/v1/podcast-transcripts/` (Cursor pagination · newest first). Base URL `https://subalytics.com/api/v1/`, API key in the `X-API-key` header; authentication, pagination, dates and errors: https://subalytics.com/docs/

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

| Parameter | Type | Description |
|---|---|---|
| `episode_sub_id` | string | The transcript of one episode |
| `sub_id` | string | Transcripts of one podcast |
| `full` | string | true = include speakers and segments; anything else or omitted = summary only |
| `updated_from` | date | Last changed on or after (use for sync) |
| `updated_to` | date | Last changed on or before |
| `limit` | int | Results per page (default 25, max 100). With full=true: default 10, max 10, since a full transcript can be 1–2 MB |
| `cursor` | string | next_cursor from the previous page |

## Response fields

| Field | Type | Description |
|---|---|---|
| `episode_sub_id` | string | The episode this transcript belongs to |
| `podcast` | object | {sub_id, podcast_name} |
| `episode` | object | {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 |
| `language` | string \| null | Language detected from the audio, e.g. en (may differ from the podcast's declared language) |
| `duration_seconds` | number \| null | Measured audio length |
| `speakers_identified` | boolean | false = speaker names haven't been identified (yet); labels still work, names are null |
| `created_at` | date | When the transcript was first produced |
| `updated_at` | date | Last change (re-transcription or speakers identified) |
| `speakers` | object | full=true only. Speaker label → {name, role, title, company} |
| `segments` | array | full=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`.
