MediaVod media.vod@1
Generated at from
openvibe-contracts v0.419.0 and
openvibe-sdk v0.161.0.
- Version
- 1.0.0
- Owner
- media
- Visibility
- first-party
- Status
- active
- Compatibility
- backward
- Schema
https://openvibe.network/contracts/media/vod.v1.json
media.vod@1: one recorded stream (VOD) as OpenVibe.Media's API answers it (server/vod/finalize.js vodPublic: GET /api/v1/:app/vods/:id, the list, and every read that returns a row). Its numeric id, its app-local user id, title and description, derived status (pending, recording, ready or failed), duration and size, the file basename, the URL its bytes play from (playback_url; hls_url is the master playlist when the object has one), thumbnail, storage provider, visibility, view counts, readiness and times. watch_id is the id openvibe.video addresses the watch page by (openvibe.video/watch?v=<watch_id>): 11 characters of URL-safe base64 from 8 random bytes, fixed for the row's life, never derived from the numeric id. More fields may be added; a consumer reads what it knows.
Fields
| Field | Type | Required | Description | Constraints |
|---|---|---|---|---|
id | integer | yes | The VOD's numeric id inside Media. Internal: a watch page is addressed by watch_id. |
|
watch_id | string | The id of its watch page on openvibe.video (openvibe.video/watch?v=<watch_id>): 8 random bytes as URL-safe base64, 64 bits. One id space across VODs and clips. Optional: a row written before the ids existed may answer without one until Media's backfill fills it. |
| |
app_id | string | yes | The tenant that owns the recording (live, media-hub, games…). | |
stream_id | integer | null | |||
managed_stream_id | integer | null | |||
user_id | string | integer | null | The owning app's local user id; it is not a Network subject id. | ||
title | string | yes |
| |
description | string | |||
status | enum | yes | Derived (db.vodStatus): recording while it is written, failed when its health quarantined it, ready once a file and a duration or size are there, pending before. |
|
duration | number | yes |
| |
duration_seconds | number |
| ||
duration_source | string | null | probe (ffprobe), remux (packet timeline) or null (stored 0). | ||
file_size | integer |
| ||
file_path | string | null | The file's basename only; a server path is never returned. | ||
playback_url | string | yes | The URL its bytes play from on openvibe.media. | |
thumbnail_url | string | null | |||
preview_url | string | null | The hover preview of this item: about 6 s, muted, 320 px wide, MP4 H.264, stored beside its thumbnail and served at /t/<name>. Null until the preview.make job has made it (audio-only, private and too-short items never get one). | ||
preview_webm_url | string | null | The same moment as preview_url, encoded as WebM (VP9, VP8 where the encoder has no VP9). Null while preview_url is. | ||
storage_provider | string | local, b2 or r2. | ||
visibility | enum | yes | public: anyone. unlisted: reached only by its exact id, never listed, noindex. private: missing to everyone but its owner and staff. |
|
is_public | boolean | yes | True only for visibility public (kept beside it for older readers). | |
health_status | string | null | |||
clips_only | boolean | |||
is_recording | boolean | |||
ai_overview | string | null | |||
ai_analyzed_at | string | null | |||
view_count | integer |
| ||
unique_views | integer |
| ||
readiness | object | The object's readiness levels (server/objects/readiness.js) when the read asked for them. | ||
readiness.metadata | boolean | |||
readiness.bytes_verified | boolean | |||
readiness.playable | boolean | |||
readiness.reason | string | null | |||
hls_url | string | The object's master playlist, when it has one (MEDIA_HLS_ENABLED). | ||
hls_expires_at | string | integer | |||
created_at | string | yes | UTC 'YYYY-MM-DD HH:MM:SS' as the store keeps it. |
Examples
From the contract's own test fixtures: valid ones validate, rejected ones must fail.
Valid: public-recording-with-watch-id
{
"id": 6203,
"watch_id": "dQw4w9WgXcQ",
"app_id": "live",
"stream_id": 912,
"managed_stream_id": 88,
"user_id": 80,
"title": "Fortnite, and the last ten minutes",
"description": "",
"status": "ready",
"duration": 5400,
"duration_seconds": 5400,
"duration_source": "probe",
"file_size": 734003200,
"file_path": "vod-live-6203-1759910400000.webm",
"playback_url": "https://openvibe.media/v/6203",
"thumbnail_url": "https://openvibe.media/t/vod-6203.jpg",
"storage_provider": "local",
"visibility": "public",
"is_public": true,
"health_status": "ok",
"clips_only": false,
"is_recording": false,
"ai_overview": null,
"ai_analyzed_at": null,
"view_count": 1321,
"unique_views": 902,
"created_at": "2026-11-06 21:00:00"
}Valid: unlisted-before-the-backfill
{
"id": 6204,
"app_id": "live",
"user_id": 80,
"title": "An unlisted rehearsal",
"description": "",
"status": "ready",
"duration": 300,
"duration_seconds": 300,
"duration_source": "probe",
"file_size": 18874368,
"file_path": "vod-live-6204-1759914000000.webm",
"playback_url": "https://openvibe.media/v/6204",
"thumbnail_url": null,
"storage_provider": "b2",
"visibility": "unlisted",
"is_public": false,
"clips_only": false,
"is_recording": false,
"view_count": 3,
"unique_views": 3,
"created_at": "2026-11-06 22:00:00"
}Rejected: watch-id-invalid-character
{
"id": 6205,
"watch_id": "dQw4w9WgXc!",
"app_id": "live",
"title": "A VOD whose watch id has a character base64url never has",
"status": "ready",
"duration": 60,
"visibility": "public",
"is_public": true,
"playback_url": "https://openvibe.media/v/6205",
"created_at": "2026-11-06 23:00:00"
}Rejected: watch-id-wrong-length
{
"id": 6206,
"watch_id": "too-short",
"app_id": "live",
"title": "A VOD with a 9-character watch id",
"status": "ready",
"duration": 60,
"visibility": "public",
"is_public": true,
"playback_url": "https://openvibe.media/v/6206",
"created_at": "2026-11-06 23:05:00"
}Validate
const contracts = require('openvibe-contracts');
contracts.validate('media.vod@1', value); // { valid, errors: [{ path, message }] }