Docs / Video

Playback & delivery

Bytes are never served direct — the playback service proxies and rewrites every HLS URI through itself, gated by a signed, expiring token (or the cookie it sets). Here's how to get a URL, embed a player, and read analytics.

signed HMAC tokenprivate originAES-128Vidstack embed

Get a playback URL + token

GET /v1/videos/{id}/playback videos:read

Start here. Returns the ready-to-play HLS master_url. For a signed video it mints and appends a short-lived HMAC token; for a public video the URL is shareable and token-free. Also returns the poster and subtitle tracks. Video must be ready (else 409).

curl
curl https://api.ollanode.com/v1/videos/vid_7Qk3.../playback \
  -H "Authorization: Bearer $OLLANODE_API_KEY"
Response
{ "master_url": "https://<playback-host>/v1/playback/vid_7Qk3.../manifest?token=eyJ...",
  "token": "eyJ...", "policy": "signed", "expires_at": "...",
  "poster_url": "https://...", "subtitles": [{"language":"en","label":"English","url":"..."}] }
Use cases
  • Fetch a fresh signed URL per viewer/session server-side.
  • Get the poster + tracks to build a custom player.
Everything below is served by the playback host (public_playback_url) — a separate host from api.ollanode.com, gated by token/cookie rather than an API key, and intentionally absent from openapi.json.

HLS manifest & cookie

GET /v1/playback/{id}/manifest?token=… token-gated

Served by the playback host (a separate data plane, not API-key auth). Fetches the master playlist from private storage and rewrites every variant URI back through itself carrying the token, and sets an HttpOnly vb_pb cookie scoped to the video so segment requests carry auth automatically — which is what lets a CDN edge cache segments. Geo rules are enforced here for both signed and public playback.

curl
curl "https://<playback-host>/v1/playback/vid_7Qk3.../manifest?token=eyJ..."
# Content-Type: application/vnd.apple.mpegurl
# Set-Cookie: vb_pb=...; Path=/v1/playback/vid_7Qk3.../; HttpOnly; Secure; SameSite=None

Segments & AES-128 keys

GET /v1/playback/{id}/seg/*path?token=… token-gated

Serves a variant playlist (URIs rewritten with the caller’s token) or streams a media segment straight from private storage — .ts (encrypted/MPEG-TS) or .m4s/init.mp4 (CMAF). Honors Range for seeking. AES-128 keys are delivered through this same route (the #EXT-X-KEY URI is rewritten to a token-gated seg/ path — there is no separate key endpoint). 401 without a valid token.

curl
curl "https://<playback-host>/v1/playback/vid_7Qk3.../seg/1080p/seg_00000.ts?token=eyJ..."
Use cases
  • Adaptive playback in hls.js / Safari.
  • CDN caches segments by path while every request re-validates the token at the edge.

Sidecar tracks (subtitles, chapters, storyboard)

Same token/cookie gate — the embed player wires these up automatically.

GET /v1/playback/{id}/subtitle/{lang}?token=… token-gated

An uploaded WebVTT subtitle track.

GET /v1/playback/{id}/chapters?token=… token-gated

WebVTT chapter cues built from the stored markers.

GET /v1/playback/{id}/storyboard.vtt?token=… token-gated

The scrub-preview cue file for hover thumbnails.

GET /v1/playback/{id}/storyboard.jpg?token=… token-gated

The storyboard sprite sheet.

Embeddable player

A self-contained Vidstack player with quality selector, storyboard hover-scrub, chapters, and captions pre-wired. Framing is allowed anywhere; a parent page can drive seeks via postMessage({ type: "ollanode-seek", seconds }).

html
<iframe
  src="https://<playback-host>/embed/vid_7Qk3...?token=eyJ..."
  allow="autoplay; fullscreen"
  style="border:0;width:100%;aspect-ratio:16/9"></iframe>

Progressive download (restricted)

GET /v1/videos/{id}/download videos:read

Presigned URLs for the progressive MP4/MP3 — only for public, non-encrypted videos. A signed or encrypted video returns 403 by design (a plaintext MP4 would defeat the gating). This is a deliberate restriction, not a bug.

curl
curl https://api.ollanode.com/v1/videos/vid_7Qk3.../download \
  -H "Authorization: Bearer $OLLANODE_API_KEY"

Analytics

GET /v1/videos/{id}/views videos:read

Raw per-video view count.

GET /v1/analytics/audience?days=30 analytics:read

Project-wide rollup: views over time, top countries, device mix, and referrers (captured off the playback path; days clamped 1–365).