Third-party API: live playback
Live integration has three steps: find the channel, make sure media is truly online, and issue short-lived URLs for the current player. Do not build a playback URL as soon as an API says that a command was accepted.
sequenceDiagram
participant Backend as Business backend
participant API as AKStream.Next
participant Device as Camera or GB device
participant Media as MediaServer
Backend->>API: Query safe channel view
opt Stream is offline and control is allowed
Backend->>API: Start channel or send GB28181 INVITE
API->>Device: Pull or request live media
Device->>Media: Publish media
end
Backend->>API: Query stream state
API-->>Backend: Online
Backend->>API: Request short playback URLs
API-->>Backend: HLS/FLV/fMP4 URLs
Query and start a channel
Read one channel:
GET /api/v2/third-party/channels/{channelId}
Authorization: Bearer ak_pat_<TOKEN>
For a regular RTSP/ONVIF channel:
POST /api/v2/third-party/channels/{channelId}/start
Authorization: Bearer ak_pat_<TOKEN>
GB28181 live view needs the SIP INVITE, RTP port, and SSRC state machine, so use the native endpoint:
POST /api/v2/gb28181/live/invite
Authorization: Bearer ak_pat_<TOKEN>
Content-Type: application/json
{
"deviceId": "34020000001320000001",
"channelId": "34020000001320000002",
"mediaServerId": "zlm-prod-01",
"rtpWithTcp": false,
"timeoutSeconds": 30
}
Starting a regular channel requires channels.manage; GB28181 live view requires devices.control. Both requests only accept work. Query the resulting stream:
GET /api/v2/third-party/streams?mediaServerId=zlm-prod-01&streamId=camera-001&state=Online
Authorization: Bearer ak_pat_<TOKEN>
GB28181 device recordings
GET /api/v2/gb28181/records/query/{taskId} returns device-side RecordInfo metadata. A device file:///, FilePath, or Address is an opaque locator, not a browser URL. The safe response hides those values and provides a playback action for every valid record:
- Call
POST /api/v2/gb28181/playback/invitewithplayback.request. - Keep the returned
session.idand wait until its app/stream is Online. - Call
POST /api/v2/third-party/gb28181/playback-sessions/{sessionId}/playback-lease. - Play a returned HTTP-FLV, HTTP-fMP4, or HLS source and renew at
renewAfter.
Listing device records requires devices.view, Playback INVITE requires devices.control, and Web playback leases require streams.play.
Request playback URLs
After the stream becomes Online, create a playback lease whose URLs remain stable:
POST /api/v2/third-party/channels/{channelId}/playback-lease
Authorization: Bearer ak_pat_<TOKEN>
Content-Type: application/json
{
"protocols": ["http-flv", "http-fmp4", "hls"],
"leaseSeconds": 120,
"absoluteLifetimeSeconds": 43200
}
Example response:
{
"leaseId": "01234567-89ab-cdef-0123-456789abcdef",
"resourceKind": "live",
"resourceId": "camera-001",
"state": "Active",
"createdAt": "2026-08-24T10:00:00Z",
"expiresAt": "2026-08-24T10:02:00Z",
"renewAfter": "2026-08-24T10:01:24Z",
"absoluteExpiresAt": "2026-08-24T22:00:00Z",
"sources": [
{
"protocol": "http-flv",
"url": "https://media.example.com/live/camera-001-main.live.flv?ak_ticket=<short-ticket>",
"contentType": "video/x-flv",
"browserNative": false,
"hint": "Use flv.js in a browser; H.265 is usually incompatible."
}
]
}
| Protocol | Best for | Client notes |
|---|---|---|
| HLS | Compatibility and internet playback | Usually higher latency; give every multi-view player its own ak_viewer |
| HTTP-FLV | Low-latency desktop browser preview | Use flv.js/MSE; H.265 is usually unsupported |
| HTTP-fMP4 | Low-latency web playback and some H.265 environments | .live.mp4 is a live connection, not a normal MP4 file |
Renewal, stopping, and errors
The sliding lease lasts 60—600 seconds and defaults to 120 seconds. Absolute lifetime is at most 12 hours and never exceeds the original API token's expiry. The server normally places renewAfter at about 70% of the current lease; clients must use the returned value instead of calculating it. At that time, the backend calls:
POST /api/v2/third-party/playback-leases/{leaseId}/renew
Authorization: Bearer ak_pat_<TOKEN>
Content-Type: application/json
{"leaseSeconds":120}
Renewal returns no new URL and does not change the existing ak_ticket. HTTP-FLV and HTTP-fMP4 are single long-lived connections, so a new URL cannot and need not be injected. HLS keeps the same URL and MediaServer cookie. After a disconnect, reconnect with the same URL as long as the lease was renewed. An expired lease cannot be revived; create a new one.
Revoke with DELETE /api/v2/third-party/playback-leases/{leaseId}. Revocation denies new connections but does not forcibly kick an established player by default. The original /playback endpoint remains compatible for short non-renewable use.
Stop a regular channel:
POST /api/v2/third-party/channels/{channelId}/stop
Authorization: Bearer ak_pat_<TOKEN>
Use /api/v2/gb28181/live/stop for a GB28181 stream. If automatic live recovery is enabled, pause that policy as required before sending BYE, or the device may be invited again.
| Status/error | Meaning | Action |
|---|---|---|
401 api_token_required |
The credential is not a valid API token | Check the token, expiry, IP allowlist, and revocation state |
403 permission_denied |
The action is outside the token scope | Ask an administrator for the minimum permission; do not auto-escalate |
409 stream_not_ready |
The channel, stream, or media node is not playable | Query channel, stream command, and stream session state instead of repeatedly issuing tickets |
409 playback_lease_conflict |
The lease expired, was revoked, reached absolute expiry, or had a concurrency conflict | Create a new lease after expiry/revocation; after a conflict, read status and retry |
| Player request gets 401/403 | The ticket expired, targets another stream, or its original grant is gone | Ask the backend for fresh authorization; do not replay the old URL |
| API succeeds but player gets 404 | The stream is gone or media host, port, vhost/app/stream is wrong | Recheck Online state and the media node's candidate address |
Production acceptance must also cover HTTPS mixed content, CORS, reverse-proxy buffering, and long-connection timeouts. The API host is not necessarily the media host.