Repository navigation
en US development third party recording
Address every recording by fileId. Third-party responses never expose server file paths, raw WebHook JSON, or node deletion command payloads.
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.
Both GET /api/v2/recording/files and GET /api/v2/third-party/recordings accept an optional sort parameter:
GET /api/v2/third-party/recordings?channelId=camera-001&page=1&pageSize=50&sort=startedAt:desc,sizeBytes:asc
Authorization: Bearer ak_pat_<TOKEN>This orders by recording start time descending, then size ascending for equal start times. Sorting applies to all matching records before pagination. Frontends can encode it with URLSearchParams.set('sort', 'startedAt:desc,sizeBytes:asc').
- Comma-separated fields have decreasing priority from left to right. Each field accepts its own
ascordesc; omitted direction meansasc. - Field names and directions are case-insensitive; surrounding whitespace is accepted.
- Missing, empty, or whitespace-only
sortpreservescreatedAt:desc. Index creation time is different from recording start time. - Nulls follow non-null values for each field. Unless
id/fileIdis explicitly present,id:ascis appended to give tied records a deterministic order. - Unknown fields, invalid directions, duplicates (including both
idandfileId), and empty terms return HTTP 400. The third-party error code isrecording_query_invalid. SQL expressions are not accepted. - Each field may occur only once; total
sortlength must not exceed 2048 characters.
| Sortable fields shared by both endpoints | Meaning |
|---|---|
id, fileId
|
Two names for the same unique file ID; choose one |
channelId, nodeId, mediaServerId
|
Channel, node, and media server IDs |
vhost, app, streamId
|
Stream routing fields |
fileName, recordDate
|
File name and recording date |
sizeBytes, durationSeconds
|
Size in bytes and duration in seconds |
fileState, canUndoDelete, deleteUndoUntil
|
File state, undo availability, and undo deadline |
existsOnDisk |
Latest known file existence |
startedAt, endedAt
|
Recording start and end times |
createdAt, updatedAt
|
Index creation and update times |
/api/v2/recording/files additionally supports sourceHook, indexSource, deletedAt, and lastScannedAt from its response. The third-party endpoint rejects these four fields. Media/download URLs, physical server paths, and internal payloads are not sortable.
Text comparison follows the database collation. Deterministic tie ordering is not a data snapshot: inserts, updates, or deletions between page requests can still change the result set. This capability requires a server containing the update; updated documentation does not upgrade an older installed build.
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.
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"
}Starting with 1.0.0.173, omitting maxSecond uses recordSecs from the channel associated with the stream. If the channel has no value, the system default applies, falling back to 3600 seconds when unset. An explicit "maxSecond": 120 takes priority; zero or negative values return HTTP 400. Video splits at a keyframe after the target duration, so actual durations may be slightly longer.
If the stream is already recording or a recording start/stop command is still pending, the manual start endpoint returns HTTP 409 with code: "recording_already_active" and an 错误 message. Display the message, call /api/v2/recording/stop, wait for completion, and then submit the new start request. Repeated starts neither change the current parameters nor automatically stop an existing recording.
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.
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.
| 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.
| 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.