> ## Documentation Index
> Fetch the complete documentation index at: https://docs.particle.pro/llms.txt
> Use this file to discover all available pages before exploring further.

# Episode archive

> Bulk download of every transcribed podcast episode, kept current daily, for loading our full history before following the stream.

The episode archive is the complete history of transcribed podcast episodes, delivered as gzip-compressed JSON Lines files. Load it once to backfill your system, then follow the [episode stream](https://docs.particle.pro/podcasts/stream.md) from where the archive leaves off. Each line is an episode as the stream delivers it with `include=all`, plus its entities and ads, so one piece of code can handle both.

> [!NOTE]
>
> The episode archive is available **by arrangement**: we enable it for your organization. Authenticate with your API key, as for the stream. A key from an organization without access is rejected with [`403 episode_archive_not_enabled`](https://docs.particle.pro/errors/episode_archive_not_enabled).

```
GET https://api.particle.pro/v1/podcasts/episodes/archive
GET https://api.particle.pro/v1/podcasts/episodes/archive/download?period=2026-09
GET https://api.particle.pro/v1/podcasts/episodes/archive/stream?period=2026-09
```

| Scope | History | Updated |
| - | - | - |
| Every transcribed episode of every podcast we cover | Everything we hold, including back catalogues imported in bulk, which the stream never carries | Daily, shortly after midnight UTC. Late episodes, imported history and corrections are folded into the days they belong to |

## What's in it

* **Every transcribed episode.** An episode is in the archive once it has a transcript, with its segments, clips, entities and ads if it has them.
* **Filed by publication date.** The archive is divided into days and months of UTC publication date. An episode published in March 2024 is in `2024-03`, whenever we ingested it.
* **One episode per line**, in publication order, as the stream's `episode` object with `include=all`, including `entities`, the knowledge graph entities discussed, most salient first, each with its `salience`, `occurrences`, `mention_lines` (the `number` of every transcript line that names it or a form extraction recognized for it) and, when the entity is a known person or company, its `entity.person` or `entity.company` reference; and `ads`, the advertising spots detected, in playback order, with the sponsor's `company_id`. Fields that the stream adds over time appear in the archive within its refresh cycle.
* **What describes the episode, not what changes.** A record holds the episode's own data: its transcript, segments, clips, the entities discussed with the transcript lines that mention each, and its ads. Values that change after the fact are left out: a person's or company's full profile, a sponsor company's profile, and anything about the show beyond its title and image. An entity or speaker that is a known person or company carries a compact reference: its `id`, which is stable and is what to join on, and a few display fields (a person's `title`, `company` and `image_url`, a company's `domain` and `ticker`) that are a snapshot from when the record was built. Fetch current values when you sync, from `GET /v1/people/{id}`, `GET /v1/companies/{id}` and `GET /v1/podcasts/{id}`.
* **Every file is a complete snapshot of its period.** When you download a day or month again, replace your copy of it. An episode missing from the new copy was removed or moved to another day.

## Load the archive

1. **List what there is.** The listing gives every month with its days, their episode counts and sizes, and a `version` for each.

   ```bash curl theme={"dark"}
   curl -s -H "X-API-Key: $PARTICLE_API_KEY" \
     https://api.particle.pro/v1/podcasts/episodes/archive
   ```

   ```bash CLI theme={"dark"}
   particle episode archive
   ```

   ```json theme={"dark"}
   {
     "as_of": "2026-10-01T01:30:05Z",
     "stream_since": "2026-10-01T01:20:05Z",
     "months": [
       {
         "month": "2026-09",
         "episodes": 1234,
         "bytes": 56789012,
         "version": "5f0c…",
         "updated_at": "2026-10-01T01:41:12Z",
         "days": [
           { "date": "2026-09-01", "episodes": 41, "bytes": 1890123, "version": "a91e…", "updated_at": "2026-10-01T01:33:40Z" }
         ]
       }
     ]
   }
   ```

2. **Download the months or days you want.** Requests are independent, so download several in parallel.

   ```bash curl theme={"dark"}
   curl -s -H "X-API-Key: $PARTICLE_API_KEY" -o 2026-09.jsonl.gz \
     "https://api.particle.pro/v1/podcasts/episodes/archive/download?period=2026-09"
   zcat 2026-09.jsonl.gz | head -1 | jq '{id, title, published_at}'
   ```

   ```bash CLI theme={"dark"}
   particle episode archive-download 2026-09 -O 2026-09.jsonl.gz
   zcat 2026-09.jsonl.gz | head -1 | jq '{id, title, published_at}'
   ```

3. **Follow the stream from `stream_since`.** The archive holds every change recorded up to `as_of`. Open the stream from `stream_since`, just before it, so nothing falls between the two. Some episodes will arrive twice; deduplicate on the episode `id`, as the stream already requires.

   ```
   GET /v1/podcasts/episodes/stream?milestone=fully_ingested&include=all&since=2026-10-01T01:20:05Z
   ```

`as_of` and `stream_since` are `null` until the archive's first full build has completed.

## Keep your copy current

The stream carries new episodes but not history: a back catalogue we import, a correction to an old transcript, or an episode we remove. Those reach you through the archive. Once a day, list it with `updated_since` set to the `as_of` of your previous sync, then download and replace each day it returns:

```bash curl theme={"dark"}
curl -s -H "X-API-Key: $PARTICLE_API_KEY" \
  "https://api.particle.pro/v1/podcasts/episodes/archive?updated_since=2026-10-01T01:30:05Z"
```

```bash CLI theme={"dark"}
particle episode archive --since 2026-10-01T01:30:05Z
```

With `updated_since`, each month lists only the days whose content changed, while its totals still describe the whole month. A day listed with `"episodes": 0` no longer has any episodes; delete your copy. A day's `version` changes only when its content does.

## Downloads

`GET /v1/podcasts/episodes/archive/download?period=…` takes a month (`2026-09`) or a day (`2026-09-29`) and returns `application/gzip`. A month is its days concatenated, which every gzip reader (`zcat`, Python's `gzip`, Go's `compress/gzip`) reads as one stream.

* **Resuming.** A day supports `Range` requests, so `curl -C -` resumes it. A month does not. On an unreliable connection, download days.
* **Unchanged files.** Every download carries an `ETag` and a `Last-Modified`. A full download's `ETag` is the period's `version`; a download narrowed with `include` has an `ETag` of its own. Send the `ETag` back in `If-None-Match`, or the `Last-Modified` time in `If-Modified-Since`, to get `304 Not Modified` when nothing changed. A `HEAD` request returns the same headers without the body.
* **Less data.** `include` keeps only the relations you name, from `transcript`, `segments`, `clips`, `entities` and `ads`; the default is all of them, unlike the stream, where it is none. Every other field is unchanged. A narrowed download is assembled as it is sent, so it is slower and has no `Content-Length` or `Range`.

```python theme={"dark"}
import gzip, json

with gzip.open("2026-09.jsonl.gz", "rt") as f:
    for line in f:  # lines can be several megabytes
        episode = json.loads(line)
        upsert(episode["id"], episode)
```

## Replay over Server-Sent Events

`GET /v1/podcasts/episodes/archive/stream?period=…` sends the same episodes as Server-Sent Events, for a consumer built around the stream that wants to load history through the same code. Each `episode` event carries a `cursor` and the `episode`. A `complete` event ends a full replay, so you can tell it from a dropped connection. To resume, reconnect with `cursor` set to the last one you processed. If the period was rebuilt in the meantime (the daily update, shortly after midnight UTC), the replay answers with an `error` event instead, because the rebuild may have added episodes before your cursor; start that period again without a cursor and deduplicate on `id`. `include` works as for downloads.

```
event: episode
data: {"cursor":"MTcyNjE…","episode":{"id":"…","title":"…","transcript":{…}}}

event: complete
data: {"period":"2026-09","episodes":1234}
```

For loading the whole archive, downloads are several times faster: they are compressed and can run in parallel.

## Shows

`GET /v1/podcasts/archive/download` returns every podcast we cover as one `application/gzip` file of JSON Lines, one show per line. It comes with the episode archive: an organization granted one is granted both. Each episode's `podcast.id` is a show's `id` here.

Each line is the podcast exactly as [`GET /v1/podcasts/{id}`](https://docs.particle.pro/api-reference/podcasts/get-a-podcast) returns it with every section requested (`include=related,recommended_guests,recommended_sponsors,coverage`): its description, publisher, popularity, bias and suitability, format, episode count, recurring speakers, topics, related shows, recommended guests and sponsors, and coverage. Each line also carries the show's `external_links`, its presences on Apple Podcasts, Spotify, YouTube, its website and social profiles, with their attributes (followers, views and the like), as `GET /v1/podcasts/{id}/external-links` returns them.

* **Rebuilt twice a day.** Values that change, popularity and audience metrics among them, are as of the current build, which `Last-Modified` dates. A build takes some minutes, and if one fails the previous file stays current, so check `Last-Modified` rather than assuming an age.
* **Cheap to poll.** Send the `ETag` back as `If-None-Match` and you get `304 Not Modified` until the next build. A download can be resumed with a `Range` request.
* **Replace, don't merge.** A show missing from a newer download has been removed.

```bash theme={"dark"}
curl -s -H "X-API-Key: $PARTICLE_API_KEY" -o podcasts.jsonl.gz \
  -D headers.txt https://api.particle.pro/v1/podcasts/archive/download
zcat podcasts.jsonl.gz | wc -l

# Later: 304 if nothing was rebuilt since.
curl -s -o /dev/null -w '%{http_code}\n' -H "X-API-Key: $PARTICLE_API_KEY" \
  -H "If-None-Match: $(grep -i '^etag' headers.txt | cut -d' ' -f2 | tr -d '\r')" \
  https://api.particle.pro/v1/podcasts/archive/download
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.