From
bafyreibefveohfqtht24oep6cn3fblgz3hufteaxupdno4xr3j5xvgnwua
indexed 2026-11-04 01:29 UTC
View this version
To
bafyreid7oqrjuv2wwuyffqaaxax6sov7wv4g6lrf3m7gfaqwplltyd644u
indexed 2026-08-20 16:29 UTC
View this version
Compatibility
breaking 24 breaking changes, 2 non-breaking changes.
Breaking changes (24)
- RequiredEdgeAdded RequiredEdgeAdded { vertex_id: "place.stream.media.finalizeLivestream:input", src: "place.stream.media.finalizeLivestream:input", tgt: "place.stream.media.finalizeLivestream:input.livestream", kind: "prop", name: Some("livestream") }
- RequiredEdgeAdded RequiredEdgeAdded { vertex_id: "place.stream.media.finalizeLivestream:output", src: "place.stream.media.finalizeLivestream:output", tgt: "place.stream.media.finalizeLivestream:output.draftUri", kind: "prop", name: Some("draftUri") }
- RemovedVertex RemovedVertex { vertex_id: "place.stream.media.finalizeLivestream:input.description" }
- RemovedVertex RemovedVertex { vertex_id: "place.stream.media.finalizeLivestream:input.endLivestream" }
- RemovedVertex RemovedVertex { vertex_id: "place.stream.media.finalizeLivestream:input.livestreams" }
- RemovedVertex RemovedVertex { vertex_id: "place.stream.media.finalizeLivestream:input.livestreams:items" }
- RemovedVertex RemovedVertex { vertex_id: "place.stream.media.finalizeLivestream:input.publish" }
- RemovedVertex RemovedVertex { vertex_id: "place.stream.media.finalizeLivestream:input.title" }
- RemovedVertex RemovedVertex { vertex_id: "place.stream.media.finalizeLivestream:output.ended" }
- RemovedVertex RemovedVertex { vertex_id: "place.stream.media.finalizeLivestream:output.ended:items" }
- RemovedVertex RemovedVertex { vertex_id: "place.stream.media.finalizeLivestream:output.livestreams" }
- RemovedVertex RemovedVertex { vertex_id: "place.stream.media.finalizeLivestream:output.livestreams:items" }
- RemovedVertex RemovedVertex { vertex_id: "place.stream.media.finalizeLivestream:output.objects" }
- RemovedEdge RemovedEdge { src: "place.stream.media.finalizeLivestream:input", tgt: "place.stream.media.finalizeLivestream:input.description", kind: "prop", name: Some("description") }
- RemovedEdge RemovedEdge { src: "place.stream.media.finalizeLivestream:input", tgt: "place.stream.media.finalizeLivestream:input.endLivestream", kind: "prop", name: Some("endLivestream") }
- RemovedEdge RemovedEdge { src: "place.stream.media.finalizeLivestream:input", tgt: "place.stream.media.finalizeLivestream:input.livestreams", kind: "prop", name: Some("livestreams") }
- RemovedEdge RemovedEdge { src: "place.stream.media.finalizeLivestream:input", tgt: "place.stream.media.finalizeLivestream:input.publish", kind: "prop", name: Some("publish") }
- RemovedEdge RemovedEdge { src: "place.stream.media.finalizeLivestream:input", tgt: "place.stream.media.finalizeLivestream:input.title", kind: "prop", name: Some("title") }
- RemovedEdge RemovedEdge { src: "place.stream.media.finalizeLivestream:input.livestreams", tgt: "place.stream.media.finalizeLivestream:input.livestreams:items", kind: "items", name: None }
- RemovedEdge RemovedEdge { src: "place.stream.media.finalizeLivestream:output", tgt: "place.stream.media.finalizeLivestream:output.ended", kind: "prop", name: Some("ended") }
- RemovedEdge RemovedEdge { src: "place.stream.media.finalizeLivestream:output", tgt: "place.stream.media.finalizeLivestream:output.livestreams", kind: "prop", name: Some("livestreams") }
- RemovedEdge RemovedEdge { src: "place.stream.media.finalizeLivestream:output", tgt: "place.stream.media.finalizeLivestream:output.objects", kind: "prop", name: Some("objects") }
- RemovedEdge RemovedEdge { src: "place.stream.media.finalizeLivestream:output.ended", tgt: "place.stream.media.finalizeLivestream:output.ended:items", kind: "items", name: None }
- RemovedEdge RemovedEdge { src: "place.stream.media.finalizeLivestream:output.livestreams", tgt: "place.stream.media.finalizeLivestream:output.livestreams:items", kind: "items", name: None }
Non-breaking changes (2)
- AddedVertex AddedVertex { vertex_id: "place.stream.media.finalizeLivestream:params" }
- AddedEdge AddedEdge { src: "place.stream.media.finalizeLivestream", tgt: "place.stream.media.finalizeLivestream:params", kind: "prop", name: Some("parameters") }
Migration guidance
Removed
RemovedVertex { vertex_id: "place.stream.media.finalizeLivestream:input.description" }RemovedVertex { vertex_id: "place.stream.media.finalizeLivestream:input.endLivestream" }RemovedVertex { vertex_id: "place.stream.media.finalizeLivestream:input.livestreams" }RemovedVertex { vertex_id: "place.stream.media.finalizeLivestream:input.livestreams:items" }RemovedVertex { vertex_id: "place.stream.media.finalizeLivestream:input.publish" }RemovedVertex { vertex_id: "place.stream.media.finalizeLivestream:input.title" }RemovedVertex { vertex_id: "place.stream.media.finalizeLivestream:output.ended" }RemovedVertex { vertex_id: "place.stream.media.finalizeLivestream:output.ended:items" }RemovedVertex { vertex_id: "place.stream.media.finalizeLivestream:output.livestreams" }RemovedVertex { vertex_id: "place.stream.media.finalizeLivestream:output.livestreams:items" }RemovedVertex { vertex_id: "place.stream.media.finalizeLivestream:output.objects" }
Added
AddedVertex { vertex_id: "place.stream.media.finalizeLivestream:params" }
Notes
- Breaking: RequiredEdgeAdded { vertex_id: "place.stream.media.finalizeLivestream:output", src: "place.stream.media.finalizeLivestream:output", tgt: "place.stream.media.finalizeLivestream:output.draftUri", kind: "prop", name: Some("draftUri") }
- Breaking: RequiredEdgeAdded { vertex_id: "place.stream.media.finalizeLivestream:input", src: "place.stream.media.finalizeLivestream:input", tgt: "place.stream.media.finalizeLivestream:input.livestream", kind: "prop", name: Some("livestream") }
- Breaking: RemovedEdge { src: "place.stream.media.finalizeLivestream:input", tgt: "place.stream.media.finalizeLivestream:input.description", kind: "prop", name: Some("description") }
- Breaking: RemovedEdge { src: "place.stream.media.finalizeLivestream:input", tgt: "place.stream.media.finalizeLivestream:input.endLivestream", kind: "prop", name: Some("endLivestream") }
- Breaking: RemovedEdge { src: "place.stream.media.finalizeLivestream:input", tgt: "place.stream.media.finalizeLivestream:input.livestreams", kind: "prop", name: Some("livestreams") }
- Breaking: RemovedEdge { src: "place.stream.media.finalizeLivestream:input", tgt: "place.stream.media.finalizeLivestream:input.publish", kind: "prop", name: Some("publish") }
- Breaking: RemovedEdge { src: "place.stream.media.finalizeLivestream:input", tgt: "place.stream.media.finalizeLivestream:input.title", kind: "prop", name: Some("title") }
- Breaking: RemovedEdge { src: "place.stream.media.finalizeLivestream:input.livestreams", tgt: "place.stream.media.finalizeLivestream:input.livestreams:items", kind: "items", name: None }
- Breaking: RemovedEdge { src: "place.stream.media.finalizeLivestream:output", tgt: "place.stream.media.finalizeLivestream:output.ended", kind: "prop", name: Some("ended") }
- Breaking: RemovedEdge { src: "place.stream.media.finalizeLivestream:output", tgt: "place.stream.media.finalizeLivestream:output.livestreams", kind: "prop", name: Some("livestreams") }
- Breaking: RemovedEdge { src: "place.stream.media.finalizeLivestream:output", tgt: "place.stream.media.finalizeLivestream:output.objects", kind: "prop", name: Some("objects") }
- Breaking: RemovedEdge { src: "place.stream.media.finalizeLivestream:output.ended", tgt: "place.stream.media.finalizeLivestream:output.ended:items", kind: "items", name: None }
- Breaking: RemovedEdge { src: "place.stream.media.finalizeLivestream:output.livestreams", tgt: "place.stream.media.finalizeLivestream:output.livestreams:items", kind: "items", name: None }
- Non-breaking: AddedEdge { src: "place.stream.media.finalizeLivestream", tgt: "place.stream.media.finalizeLivestream:params", kind: "prop", name: Some("parameters") }
Changes
11
{22
"$type": "com.atproto.lexicon.schema",33
"defs": {44
"main": {5
"description": "Turn a finished livestream into a VOD. The server concatenates the MUXL segments it recorded for the livestream(s) into a single content blob, derives the playback sidecars, and publishes the place.stream.media.track records. By default it leaves a draft VOD the streamer publishes later via place.stream.vod.publishDraft; with publish set it publishes the place.stream.video record as soon as the VOD is finalized. The caller must be the streamer, or a moderator they have granted livestream.manage; every record is written with the streamer's session.",5
"description": "Turn a finished livestream into a VOD. The server concatenates the MUXL segments it recorded for the livestream into a single content blob, derives the playback sidecars, and publishes the place.stream.media.track records. Processing completes server-side and creates a draft VOD; the client does not need to poll or publish — the user publishes the draft later via place.stream.vod.publishDraft. Returns the draft's ats:// URI so the client can navigate to it, alongside an uploadId for backwards compatibility.",66
"errors": [77
{8
"description": "No livestream with the given URI is known to this node, or the livestreams belong to different streamers.",8
"description": "No livestream with the given URI is known, or it does not belong to the authenticated user.",99
"name": "LivestreamNotFound"1010
},1111
{1212
"description": "The livestream has no recorded MUXL segments to finalize (recording was not enabled, or none completed).",1313
"name": "NoRecording"14
},15
{16
"description": "The caller is neither the streamer nor a moderator with livestream.manage from them.",17
"name": "NotPermitted"1814
}1915
],2016
"input": {2117
"encoding": "application/json",2218
"schema": {2319
"properties": {24
"description": {25
"description": "Description of the video record.",26
"maxLength": 10000,27
"type": "string"28
},29
"endLivestream": {30
"default": false,31
"description": "Also end any of the livestream records that were never stopped, so the streamer's page stops reading as live.",32
"type": "boolean"33
},3420
"livestream": {35
"description": "AT-URI of the place.stream.livestream record to finalize into a VOD. Either this or livestreams is required.",21
"description": "AT-URI of the place.stream.livestream record to finalize into a VOD. Must belong to the authenticated user.",3622
"format": "at-uri",3723
"type": "string"38
},39
"livestreams": {40
"description": "Several livestream records whose recordings make up one VOD: a streamer who started a new record mid-stream splits the recording across them. Recordings are concatenated in the records' creation order, whatever order they are listed in. All must belong to one streamer.",41
"items": {42
"format": "at-uri",43
"type": "string"44
},45
"type": "array"46
},47
"publish": {48
"default": false,49
"description": "Publish the place.stream.video record as soon as the VOD is finalized, instead of leaving a draft.",50
"type": "boolean"51
},52
"title": {53
"description": "Title of the video record; the first livestream's title when empty.",54
"maxLength": 1000,55
"type": "string"5624
}5725
},58
"required": [],26
"required": [27
"livestream"28
],5929
"type": "object"6030
}6131
},6232
"output": {6333
"encoding": "application/json",6434
"schema": {6535
"properties": {6636
"draftUri": {67
"description": "The ats:// URI of the draft VOD created for this finalize, when publish is not set. The draft reaches status 'ready' when processing completes.",37
"description": "The ats:// URI of the draft VOD created for this finalize. The draft reaches status 'ready' when processing completes; the user publishes it from the Drafts tab via place.stream.vod.publishDraft.",6838
"type": "string"6939
},70
"ended": {71
"description": "Livestream records that are now ended (already, or by endLivestream).",72
"items": {73
"format": "at-uri",74
"type": "string"75
},76
"type": "array"77
},78
"livestreams": {79
"description": "The livestream records the VOD is made of, in recording order.",80
"items": {81
"format": "at-uri",82
"type": "string"83
},84
"type": "array"85
},86
"objects": {87
"description": "How many recorded objects will be concatenated.",88
"type": "integer"89
},9040
"uploadId": {9141
"description": "Identifier for the finalize job. Retained for backwards compatibility; the draft flow no longer requires the client to poll getUploadStatus.",9242
"type": "string"9343
}9444
},9545
"required": [96
"uploadId"46
"uploadId",47
"draftUri"9748
],9849
"type": "object"9950
}10051
},52
"parameters": null,10153
"type": "procedure"10254
}10355
},10456
"id": "place.stream.media.finalizeLivestream",10557
"lexicon": 110658
}