live.voxport.podcast.episode
{
"$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
}
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)
- 2026-09-09 15:42 UTC (current)
- 2026-09-01 18:32 UTC diff
Referenced Schemas (1)
Similar Lexicons
Lexicons whose schemas describe something close to this one. Check them before publishing a new one that overlaps.
-
place.pod.episode record
A single podcast episode.
-
org.atpodcasting.episode record
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.
-
pink.vase.pod.episode record
A podcast episode belonging to a show.
-
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.
-
live.voxport.podcast.series record
A podcast series/channel owned by a creator on VoxPort