MediaClip media.clip@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/clip.v1.json
media.clip@1: one clip as OpenVibe.Media's API answers it (server/vod/clips-routes.js clipPublic: GET /api/v1/:app/clips/:id, the list, create, trim and update). Its numeric id, the recording it was cut from, the clipper and the clipped channel, title and status (processing, ready or failed), its window in the source, duration, the file basename, the URL its bytes play from, thumbnail, visibility, whether an automation cut it (auto_generated) and its view counts. 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, in the same id space as a VOD's, fixed for the row's life, never derived from the numeric id. More fields may be added.
Fields
| Field | Type | Required | Description | Constraints |
|---|---|---|---|---|
id | integer | yes | The clip'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 — a watch id never names both a VOD and a clip. 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 clip (live, media-hub…). | |
vod_id | integer | null | The recording it was cut from, when it has one. | ||
stream_id | integer | null | |||
user_id | string | integer | null | The clipper's app-local user id; it is not a Network subject id. | ||
channel_user_id | string | integer | null | The clipped channel's app-local user id (who the clip is of). | ||
title | string | yes |
| |
description | string | |||
status | enum | yes | processing while the cut runs, ready when its file is there, failed when the cut failed (cut_error, and will_retry while a retry is queued). |
|
cut_error | string | null | |||
will_retry | boolean | |||
start_time | number | The clip's start in the source recording, seconds. |
| |
end_time | number |
| ||
duration | number |
| ||
duration_seconds | number |
| ||
file_path | string | null | The file's basename only. | ||
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 | |||
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 | ||
auto_generated | boolean | True when an automation (Live's AI moments) cut it, not a person. An AI clip is noindex and never in a sitemap. | ||
ai_overview | string | null | |||
ai_analyzed_at | string | null | |||
view_count | integer |
| ||
unique_views | integer |
| ||
readiness | object | The object's readiness levels 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. | ||
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: ai-clip-before-the-backfill
{
"id": 495,
"app_id": "live",
"vod_id": 6203,
"stream_id": 912,
"user_id": 80,
"channel_user_id": 80,
"title": "AI clip: the best thirty seconds",
"description": "",
"status": "ready",
"start_time": 3600,
"end_time": 3630,
"duration": 30,
"duration_seconds": 30,
"file_path": "clip-live-495-1759915000000.webm",
"playback_url": "https://openvibe.media/c/495",
"thumbnail_url": null,
"storage_provider": "local",
"visibility": "public",
"is_public": true,
"auto_generated": true,
"view_count": 0,
"unique_views": 0,
"created_at": "2026-11-06 21:50:00"
}Valid: person-made-clip-with-watch-id
{
"id": 494,
"watch_id": "x7Kp2mQaB9c",
"app_id": "live",
"vod_id": 6203,
"stream_id": 912,
"user_id": 57,
"channel_user_id": 80,
"title": "That landing",
"description": "",
"status": "ready",
"start_time": 1890.5,
"end_time": 1920.5,
"duration": 30,
"duration_seconds": 30,
"file_path": "clip-live-494-1759914000000.webm",
"playback_url": "https://openvibe.media/c/494",
"thumbnail_url": "https://openvibe.media/t/clip-494.jpg",
"storage_provider": "local",
"visibility": "public",
"is_public": true,
"auto_generated": false,
"ai_overview": null,
"ai_analyzed_at": null,
"view_count": 412,
"unique_views": 318,
"created_at": "2026-11-06 21:40:00"
}Rejected: unknown-visibility
{
"id": 497,
"watch_id": "dQw4w9WgXcQ",
"app_id": "live",
"title": "A clip with a visibility nobody offers",
"status": "ready",
"visibility": "friends",
"is_public": false,
"playback_url": "https://openvibe.media/c/497",
"created_at": "2026-11-06 23:15:00"
}Rejected: watch-id-not-url-safe
{
"id": 496,
"watch_id": "dQw4w9WgXcQ/",
"app_id": "live",
"title": "A clip whose watch id has a slash",
"status": "ready",
"visibility": "public",
"is_public": true,
"playback_url": "https://openvibe.media/c/496",
"created_at": "2026-11-06 23:10:00"
}Validate
const contracts = require('openvibe-contracts');
contracts.validate('media.clip@1', value); // { valid, errors: [{ path, message }] }