Skip to content

Playback API

A short-lived, signed URL a player loads to watch a stream live or, once it has ended, its recording. Mint one per viewer session from your server; never cache one for everyone.

This page is generated from the OpenAPI specification; the same text is inMarkdown for tools and AI assistants.

Get a playback URL

GET/v1/streams/{playback_id}/playback

A signed HLS URL for a player, valid for six hours: the live stream while it is on air, and the recording once it has ended.

Call it from your server for each viewer session. For a private stream, pass viewer=1 with the viewer’s access code (and their IP address in X-Viewer-IP, so wrong codes are limited per viewer rather than against your server). A call without viewer=1 is your own server and is trusted.

When the live room is on, the response also carries a viewer pass for it (room), and, when captions are on, the caption tracks.

Path parameters

NameTypeDescription
playback_idrequiredstring

The stream’s playback_id.

Query parameters

NameTypeDescription
viewerstring

1 when this pass is for a viewer and should be checked against the stream’s access code. Left out, the call is trusted as your own.

One of "1", "true".

access_codestring

The viewer’s access code for a private stream (or send X-Access-Code).

viewer_ipstring

The viewer’s IP address (or send X-Viewer-IP).

Headers

NameTypeDescription
X-Viewer-Namestring

The name of a viewer you have signed in, percent-encoded UTF-8, 1-40 characters. Shown in the room. Send it only for a viewer whose identity you have verified.

X-Viewer-Memberstring

1 to mark the named viewer as a member of the customer’s community. Only with X-Viewer-Name.

One of "1".

X-Access-Codestring

The viewer’s access code for a private stream.

X-Viewer-IPstring

The viewer’s IP address, so wrong access codes are limited per viewer.

Response 200

The playback URL, when it expires, and the room pass and caption tracks when they apply.

Fields
NameTypeDescription
playback_urlrequiredstring

The HLS URL a player loads. A credential; mint one per viewer session.

expires_atrequiredstring (date-time)
roomobject
room.urlrequiredstring

The room’s WebSocket URL.

room.tokenrequiredstring

The pass. A credential.

room.expires_atrequiredstring (date-time)
captionsarray of object
captions[].langrequiredstring
captions[].namerequiredstring
captions[].kindrequiredstring

One of "source", "translation".

captions[].betaboolean

Errors

StatusCodeMeaning
400invalid_viewer

viewer is not 1 or true.

400invalid_viewer_name

X-Viewer-Name is not a 1-40 character name, percent-encoded.

400invalid_viewer_member

X-Viewer-Member is not 1, or was sent without X-Viewer-Name.

403access_code_required

The stream is private and no access code was given.

403access_code_invalid

That access code is not this stream’s.

404not_found

No such stream in your organization.

409not_published_yet

No video has arrived for this stream yet.

410recording_deleted

The stream has ended and its recording was deleted.

410recording_expired

The stream has ended and its recording is past its 30 days.

429too_many_attempts

Too many wrong access codes from this viewer; try again after Retry-After seconds.

503busy

Too many viewers are being checked at once; retry after Retry-After seconds.

503playback_unconfigured

Playback is not available on this deployment.

Terminal window
curl "https://api.cardinalstreaming.com/v1/streams/1846bdac2d8c0ce0e846d4a3817012c9/playback" \
-H "Authorization: Bearer $CARDINAL_API_KEY"
Response 200
{
"playback_url": "https://media.cardinal.stream/1846bdac2d8c0ce0e846d4a3817012c9/master.m3u8?t=v1.eyJw...",
"expires_at": "2026-09-20T20:41:07Z"
}