Third-party API: recordings, clips, and deletion
Address every recording by fileId. Third-party responses never expose server file paths, raw WebHook JSON, or node deletion command payloads.
Search, play, and download
Search by channel and time:
GET /api/v2/third-party/recordings?channelId=camera-001&startTime=2026-08-24T08:00:00%2B08:00&endTime=2026-08-24T10:00:00%2B08:00&page=1&pageSize=50
Authorization: Bearer ak_pat_<TOKEN>
startTime/endTime use interval overlap: a recording is returned when any part overlaps the requested window. Add fileState=Available to list only playable files.
Rows never contain a server FilePath or file:/// value. Each row provides playbackLinkEndpoint, playbackLeaseEndpoint, and downloadLinkEndpoint. These are POST actions for the next step, not pre-issued tickets; prefer playbackLeaseEndpoint for playback.
For long recordings or a native <video> element, create a playback lease whose URL stays stable:
POST /api/v2/third-party/recordings/{fileId}/playback-lease
Authorization: Bearer ak_pat_<TOKEN>
Content-Type: application/json
{"leaseSeconds":120,"absoluteLifetimeSeconds":43200}
At renewAfter, call /api/v2/third-party/playback-leases/{leaseId}/renew. Renewal changes only timestamps, so later Range requests keep the same URL without resetting video.src or restoring currentTime. Use /playback-link for short non-renewable playback and /download-link for downloads. Playback requires recordings.play; download requires recordings.download. The credentials are not interchangeable, and download links are not renewable.
Start and stop recording
Use the domain endpoint to start manual recording:
POST /api/v2/recording/start
Authorization: Bearer ak_pat_<TOKEN>
Content-Type: application/json
{
"channelId": "camera-001",
"mediaServerId": "zlm-prod-01",
"app": "live",
"streamId": "camera-001-main",
"vhost": "__defaultVhost__",
"recordSource": "Manual"
}
Call /api/v2/recording/stop to stop, then query /api/v2/recording/sessions. A successful command does not mean the MP4 has closed. Confirm the recording session's final state, WebHook processing, and an available file in /third-party/recordings.
Clip and merge
Create a job:
POST /api/v2/third-party/cut-merge/tasks
Authorization: Bearer ak_pat_<TOKEN>
Content-Type: application/json
{
"channelId": "camera-001",
"mainId": "camera-001",
"app": "live",
"vhost": "__defaultVhost__",
"startTime": "2026-08-24T08:15:00+08:00",
"endTime": "2026-08-24T08:35:00+08:00"
}
The third-party endpoint rejects callbackUrl so the legacy callback cannot send physical paths to an arbitrary host. Poll:
GET /api/v2/third-party/cut-merge/tasks/{taskId}
Authorization: Bearer ak_pat_<TOKEN>
After taskStatus=Closed, use /playback-lease for long playback, or /playback-link and /download-link for short playback and downloads. A job may cover at most 120 minutes. If selected files span physical nodes, narrow the time range or archive them to one node first.
Regular recording and clip-task queries also return only platform /media and /download HTTP actions. They do not expose physical paths, raw Hook/plan JSON, callback URLs, or internal command IDs.
Soft-delete, restore, and hard-delete
| Action | Endpoint | Actual effect |
|---|---|---|
| Soft-delete | POST /api/v2/third-party/recordings/soft-delete |
Hides recordings and starts the recovery window without deleting disk files |
| Restore | POST /api/v2/third-party/recordings/restore |
Restores only recoverable recordings whose physical file can still be confirmed |
| Hard-delete | POST /api/v2/third-party/recordings/hard-delete |
Creates an auditable node deletion command; success does not mean the file is already gone |
| Delete clip output | DELETE /api/v2/third-party/cut-merge/tasks/{taskId} |
Deletes the job output by default without returning a server path |
Batch request body:
{
"fileIds": [
"01234567-89ab-cdef-0123-456789abcdef",
"11234567-89ab-cdef-0123-456789abcdef"
]
}
One request accepts at most 200 IDs. succeeded means the current stage succeeded; failed contains per-item reasons. After hard-delete, keep querying recording state or the related node command until FileState=Deleted. Do not erase your business record merely because HTTP returned 200.
Common states and actions
| State | Meaning | Recommended action |
|---|---|---|
Available |
The file can be played or downloaded | Request a short-lived URL |
SoftDeleted |
Hidden and possibly recoverable | Read canUndoDelete/deleteUndoUntil |
DeleteRequested |
A node hard-delete command exists | Wait for the result; do not resubmit blindly |
Deleted |
Physical deletion is complete | Keep audit history and stop playback/download |
Missing |
The index exists but the disk file is unavailable | Check mounts, node state, and scan results |
DeleteFailed |
The command or file operation failed | Keep the TraceId and reason, fix the cause, then retry |
| Playback says the current node cannot access the file | The recording belongs to a remote node without a shared mount | Route the request to the owning node or deploy a shared managed recording root |
Soft-delete, hard-delete, and deleting clip outputs require recordings.delete. Restore, recording start/stop, and clip/merge require recordings.manage. Before deletion, your UI should clearly show file count, time range, and irreversible impact.