live.voxport.podcast.episode

voxport.live

{
  "$type": "com.atproto.lexicon.schema",
  "defs": {
    "chapter": {
      "properties": {
        "endTime": {
          "description": "End time in seconds (optional)",
          "type": "integer"
        },
        "hidden": {
          "description": "Whether the chapter is hidden from the table of contents (Podcasting 2.0 toc:false)",
          "type": "boolean"
        },
        "image": {
          "format": "uri",
          "type": "string"
        },
        "startTime": {
          "description": "Start time in seconds",
          "type": "integer"
        },
        "title": {
          "maxLength": 256,
          "type": "string"
        },
        "url": {
          "description": "Chapter link URL (Podcasting 2.0 chapter url)",
          "format": "uri",
          "type": "string"
        }
      },
      "required": [
        "title",
        "startTime"
      ],
      "type": "object"
    },
    "main": {
      "description": "A podcast episode belonging to a series",
      "key": "tid",
      "record": {
        "properties": {
          "audio": {
            "accept": [
              "audio/mpeg",
              "audio/mp4",
              "audio/wav",
              "audio/ogg",
              "audio/aac"
            ],
            "description": "Audio file reference",
            "maxSize": 524288000,
            "type": "blob"
          },
          "audioLength": {
            "description": "Byte size of the audio file when using audioUrl. Required for a valid RSS enclosure — without this, a firehose consumer cannot reconstruct the feed from records alone.",
            "minimum": 0,
            "type": "integer"
          },
          "audioType": {
            "description": "MIME type of the audio file when using audioUrl. Pairs with audioLength for RSS enclosure reconstruction.",
            "knownValues": [
              "audio/mpeg",
              "audio/mp4",
              "audio/wav",
              "audio/ogg",
              "audio/aac"
            ],
            "maxLength": 64,
            "type": "string"
          },
          "audioUrl": {
            "description": "External audio URL (if not using blob)",
            "format": "uri",
            "type": "string"
          },
          "blueskyPostRef": {
            "description": "Reference to the Atmosphere cross-post (app.bsky.feed.post) for this episode. Set when the episode is auto-cross-posted, enabling custom feed operators to discover the cross-post from the episode record.",
            "ref": "com.atproto.repo.strongRef",
            "type": "ref"
          },
          "chapters": {
            "description": "Episode chapters/timestamps",
            "items": {
              "ref": "#chapter",
              "type": "ref"
            },
            "maxLength": 100,
            "type": "array"
          },
          "createdAt": {
            "format": "datetime",
            "type": "string"
          },
          "duration": {
            "description": "Duration in seconds",
            "minimum": 0,
            "type": "integer"
          },
          "episodeNumber": {
            "description": "Episode number in series",
            "minimum": 1,
            "type": "integer"
          },
          "episodeType": {
            "default": "full",
            "description": "Episode type per RSS spec",
            "knownValues": [
              "full",
              "trailer",
              "bonus"
            ],
            "maxLength": 16,
            "type": "string"
          },
          "explicit": {
            "description": "Whether episode is explicit",
            "type": "boolean"
          },
          "image": {
            "accept": [
              "image/png",
              "image/jpeg"
            ],
            "description": "Episode-specific cover art",
            "maxSize": 2097152,
            "type": "blob"
          },
          "importedGuid": {
            "description": "Original GUID from RSS feed (for imported episodes)",
            "maxLength": 2048,
            "type": "string"
          },
          "persons": {
            "description": "People associated with this episode — hosts, guests, co-hosts (Podcasting 2.0 podcast:person)",
            "items": {
              "ref": "#person",
              "type": "ref"
            },
            "maxLength": 50,
            "type": "array"
          },
          "publishedAt": {
            "description": "Publication date (null = draft)",
            "format": "datetime",
            "type": "string"
          },
          "seasonNumber": {
            "description": "Season number",
            "minimum": 1,
            "type": "integer"
          },
          "series": {
            "description": "Reference to parent series (uri + optional cid)",
            "ref": "live.voxport.podcast.series#seriesRef",
            "type": "ref"
          },
          "soundbites": {
            "description": "Short clip markers for apps to surface (Podcasting 2.0 podcast:soundbite)",
            "items": {
              "ref": "#soundbite",
              "type": "ref"
            },
            "maxLength": 20,
            "type": "array"
          },
          "summary": {
            "description": "Episode description/show notes (supports markdown)",
            "maxLength": 10000,
            "type": "string"
          },
          "tags": {
            "description": "Episode tags/keywords",
            "items": {
              "maxLength": 64,
              "type": "string"
            },
            "maxLength": 20,
            "type": "array"
          },
          "title": {
            "description": "Episode title",
            "maxLength": 256,
            "type": "string"
          },
          "transcript": {
            "description": "Episode transcript (singular — deprecated, prefer transcripts array)",
            "ref": "#transcript",
            "type": "ref"
          },
          "transcripts": {
            "description": "Episode transcripts — multiple entries for different languages/formats (Podcasting 2.0 podcast:transcript). Preferred over the singular transcript field.",
            "items": {
              "ref": "#transcript",
              "type": "ref"
            },
            "maxLength": 20,
            "type": "array"
          },
          "updatedAt": {
            "format": "datetime",
            "type": "string"
          }
        },
        "required": [
          "series",
          "title",
          "createdAt"
        ],
        "type": "object"
      },
      "type": "record"
    },
    "person": {
      "properties": {
        "did": {
          "description": "ATProto DID if the person has a verified identity",
          "format": "did",
          "type": "string"
        },
        "group": {
          "description": "Group from the Podcast Taxonomy Project (e.g. cast, writing, visuals). Defaults to 'cast' if absent.",
          "maxLength": 64,
          "type": "string"
        },
        "handle": {
          "description": "ATProto handle (e.g. alice.bsky.social) if the person has a Bluesky account",
          "format": "handle",
          "type": "string"
        },
        "image": {
          "description": "Profile image URL (maps to podcast:person img attribute)",
          "format": "uri",
          "type": "string"
        },
        "name": {
          "description": "Full name or alias of the person (spec: max 128 chars)",
          "maxLength": 128,
          "type": "string"
        },
        "role": {
          "description": "Role from the Podcast Taxonomy Project (e.g. host, guest, co-host). Defaults to 'host' if absent.",
          "maxLength": 64,
          "type": "string"
        },
        "url": {
          "description": "External profile URL (maps to podcast:person href attribute)",
          "format": "uri",
          "type": "string"
        }
      },
      "required": [
        "name"
      ],
      "type": "object"
    },
    "soundbite": {
      "properties": {
        "duration": {
          "description": "Duration in fractional seconds (e.g. '60.0', '42.25'). Matches Podcasting 2.0 spec exactly.",
          "maxLength": 16,
          "type": "string"
        },
        "startTime": {
          "description": "Start time in fractional seconds (e.g. '73.0', '1234.5'). Matches Podcasting 2.0 spec exactly.",
          "maxLength": 16,
          "type": "string"
        },
        "title": {
          "description": "Title/label for the soundbite (spec: max 128 chars)",
          "maxLength": 128,
          "type": "string"
        }
      },
      "required": [
        "startTime",
        "duration"
      ],
      "type": "object"
    },
    "transcript": {
      "properties": {
        "language": {
          "description": "Language of the transcript (defaults to feed language if absent)",
          "format": "language",
          "type": "string"
        },
        "rel": {
          "description": "If 'captions', the file is a closed captions file with time codes",
          "knownValues": [
            "captions"
          ],
          "maxLength": 16,
          "type": "string"
        },
        "type": {
          "description": "MIME type of the transcript file",
          "knownValues": [
            "text/plain",
            "text/html",
            "text/vtt",
            "application/x-subrip",
            "application/json"
          ],
          "maxLength": 64,
          "type": "string"
        },
        "url": {
          "description": "URL of the transcript file",
          "format": "uri",
          "type": "string"
        }
      },
      "required": [
        "url",
        "type"
      ],
      "type": "object"
    }
  },
  "description": "A podcast episode belonging to a series",
  "id": "live.voxport.podcast.episode",
  "lexicon": 1
}

Validate Record

Validate a record against live.voxport.podcast.episode

Validation Options
Automatically resolve and include external schemas for full validation
Treat any remaining unresolved references as valid

Metadata

DID
did:plc:hhtgwctzcuhlkqrxu526sco5
CID
bafyreibtvk5eds3knox6aw4bsxt4a5x7hldl4a3dz7d3e2gljgdx5fymoy
Indexed At
2026-09-09 15:42 UTC
AT-URI
at://did:plc:hhtgwctzcuhlkqrxu526sco5/com.atproto.lexicon.schema/live.voxport.podcast.episode

Version History (2 versions)

Referenced Schemas (1)

Similar Lexicons

Lexicons whose schemas describe something close to this one. Check them before publishing a new one that overlaps.

  • A single podcast episode.

  • A podcast episode. Record key is a UUIDv5 derived from the podcast GUID (as namespace) and the episode's feedItemGuid (as name), enabling deterministic lookup from RSS feed metadata.

  • A podcast episode belonging to a show.

  • org.swappulse.podcastEpisode recordnot from the namespace authority

    A podcast episode (often derived from a voice space recording), mirrored to AT Protocol as a real org.swappulse.podcastEpisode record so episodes are portable and playable across instances.

  • A podcast series/channel owned by a creator on VoxPort

Lexicon Garden

@