{"openapi":"3.1.0","info":{"title":"VideoNest API","description":"The VideoNest API reads and updates channels, videos, captions, feeds, and analytics.\nUpload videos with `POST /uploads`, PUT the returned parts directly to storage,\nthen call `POST /uploads/{id}/complete`. Upload a thumbnail with\n`POST /videos/{id}/thumbnail`. Upload writes require `write_videos` and permission\nto edit the channel.\n\n**Authentication.** Send a scoped API key as `Authorization: Bearer vn_live_...`.\nCreate keys in the VideoNest dashboard. A key acts as its owner, narrowed to the\nscopes and channels chosen when the key was created. Use keys from a server, never\nfrom a browser.\n\n**Objects.** Every object has a prefixed `id` (`ws_`, `chn_`, `vid_`, `feed_`,\n`key_`, `upl_`), an `object` type name, and a `created_at` time. Times are RFC 3339 in UTC\n(`2026-09-01T12:00:00Z`) and dates are `YYYY-MM-DD`. Objects are flat: a field is\nnever a JSON object. A related resource is an id string, for example\n`\"channel\": \"chn_4412\"`.\n\n**Lists.** List endpoints return `{\"object\": \"list\", \"has_more\", \"next_cursor\", \"data\"}`,\nnewest first by id. Use `limit` (1 to 100, default 50). When `has_more` is true, send\n`next_cursor` back as `cursor`, with the same filters, to get the next page. A `Link`\nheader with `rel=\"next\"` holds the same request as a URL.\n\n**Request size.** A request body over 1 MiB is refused with 413 `request_too_large`.\nVideo file parts go directly to the signed storage URLs and do not count toward\nthis limit. Thumbnail multipart requests, including form overhead, must fit it.\n\n**Errors.** Failures return an HTTP status and\n`{\"error\": {\"type\", \"code\", \"message\", \"param\", \"doc_url\", \"request_id\"}}`.\nA 403 for a missing scope also carries `required_scope`.\n\n**Updates.** Change an object with `PATCH`. Send only the fields to change: an omitted\nfield stays as it is, and `null` clears a field that may be empty.\n\n**Idempotency.** Send an `Idempotency-Key` header with a PATCH or POST to make it safe\nto retry. Results are kept 24 hours.\n\n**Rate limits.** Each key may send 25 requests per second (5 per second for\nanalytics). Responses carry `RateLimit-Limit`, `RateLimit-Remaining`, and\n`RateLimit-Reset`; a 429 carries `Retry-After`.\n\n**Request ids.** Every response carries `Request-Id`. Quote it when you contact support.\n","version":"2026-09-30"},"servers":[{"url":"https://api1.videonest.co/v1"}],"paths":{"/workspace":{"get":{"tags":["Workspace"],"summary":"Retrieve the workspace","description":"Returns the workspace the API key is tied to. A key created outside a workspace has none and gets a 404.\n\nRequired scope: `read_workspace`.","operationId":"workspace.retrieve","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Workspace"}}}},"401":{"description":"The API key is missing, invalid, revoked, or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The key lacks the required scope (`missing_scope`) or may not be used from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such object, or the key cannot see it (`resource_missing`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests. Wait for `Retry-After` seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"ApiKey":["read_workspace"]}],"x-required-scopes":["read_workspace"]}},"/channels":{"get":{"tags":["Channels"],"summary":"List channels","description":"Returns the channels the key can reach, newest first. A key tied to a workspace sees that workspace's channels; a key limited to particular channels sees only those.\n\nRequired scope: `read_channels`.","operationId":"channels.list","security":[{"ApiKey":["read_channels"]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Number of objects to return, between 1 and 100.","default":50,"title":"Limit"},"description":"Number of objects to return, between 1 and 100."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"The `next_cursor` of the previous page. Send the same filters as the request that returned it.","title":"Cursor"},"description":"The `next_cursor` of the previous page. Send the same filters as the request that returned it."}],"responses":{"200":{"description":"A page of results.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChannelList"}}},"headers":{"Link":{"description":"Present when `has_more` is true: the URL of the next page, `<https://api1.videonest.co/v1/videos?limit=50&cursor=...>; rel=\"next\"`.","schema":{"type":"string"}}}},"400":{"description":"The request has an invalid or missing parameter (`parameter_invalid`), or a `cursor` that does not belong to this query (`cursor_invalid`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"The API key is missing, invalid, revoked, or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The key lacks the required scope (`missing_scope`) or may not be used from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests. Wait for `Retry-After` seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"x-required-scopes":["read_channels"]}},"/channels/{channel_id}":{"get":{"tags":["Channels"],"summary":"Retrieve a channel","description":"Returns one channel. A channel the key cannot reach returns 404.\n\nRequired scope: `read_channels`.","operationId":"channels.retrieve","security":[{"ApiKey":["read_channels"]}],"parameters":[{"name":"channel_id","in":"path","required":true,"schema":{"type":"string","title":"Channel Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Channel"}}}},"400":{"description":"The request has an invalid or missing parameter (`parameter_invalid`), or a `cursor` that does not belong to this query (`cursor_invalid`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"The API key is missing, invalid, revoked, or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The key lacks the required scope (`missing_scope`) or may not be used from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such object, or the key cannot see it (`resource_missing`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests. Wait for `Retry-After` seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"x-required-scopes":["read_channels"]},"patch":{"tags":["Channels"],"summary":"Update a channel","description":"Changes the channel's `title` (its name) or `description`. Send only the fields to change. No other channel setting can be changed through the API. A title another channel already uses returns 409.\n\nRequired scope: `write_channels`.","operationId":"channels.update","security":[{"ApiKey":["write_channels"]}],"parameters":[{"name":"channel_id","in":"path","required":true,"schema":{"type":"string","title":"Channel Id"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","minLength":1,"maxLength":255},{"type":"null"}],"description":"Makes the request safe to repeat. A repeat with the same key and body within 24 hours returns the first response and sets `Idempotent-Replayed: true`. The same key with a different body is a 400; a repeat while the first request runs is a 409.","title":"Idempotency-Key"},"description":"Makes the request safe to repeat. A repeat with the same key and body within 24 hours returns the first response and sets `Idempotent-Replayed: true`. The same key with a different body is a 400; a repeat while the first request runs is a 409."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChannelUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Channel"}}}},"400":{"description":"The request has an invalid or missing parameter (`parameter_invalid`), or a `cursor` that does not belong to this query (`cursor_invalid`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"The API key is missing, invalid, revoked, or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The key lacks the required scope (`missing_scope`) or may not be used from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such object, or the key cannot see it (`resource_missing`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"A request with this Idempotency-Key is still running, or upload completion has already started.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"The request body is larger than 1 MiB (`request_too_large`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests. Wait for `Retry-After` seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"x-required-scopes":["write_channels"]}},"/videos":{"get":{"tags":["Videos"],"summary":"List videos","description":"Returns videos in the channels the key can reach, newest first. Filter by `channel`, by `evergreen_eligible`, or by ingestion time with `created_at_min` and `created_at_max` (RFC 3339, both inclusive). Videos VideoNest has no ingestion time for are left out when either time is set. `evergreen_eligible=false` includes videos never marked.\n\nRequired scope: `read_videos`.","operationId":"videos.list","security":[{"ApiKey":["read_videos"]}],"parameters":[{"name":"channel","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Only videos in this channel, for example `chn_4412`.","title":"Channel"},"description":"Only videos in this channel, for example `chn_4412`."},{"name":"created_at_min","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Only videos ingested at or after this time (RFC 3339).","title":"Created At Min"},"description":"Only videos ingested at or after this time (RFC 3339)."},{"name":"created_at_max","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Only videos ingested at or before this time (RFC 3339).","title":"Created At Max"},"description":"Only videos ingested at or before this time (RFC 3339)."},{"name":"evergreen_eligible","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Only videos with this evergreen flag. `false` also matches videos never marked.","title":"Evergreen Eligible"},"description":"Only videos with this evergreen flag. `false` also matches videos never marked."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Number of objects to return, between 1 and 100.","default":50,"title":"Limit"},"description":"Number of objects to return, between 1 and 100."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"The `next_cursor` of the previous page. Send the same filters as the request that returned it.","title":"Cursor"},"description":"The `next_cursor` of the previous page. Send the same filters as the request that returned it."}],"responses":{"200":{"description":"A page of results.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VideoList"}}},"headers":{"Link":{"description":"Present when `has_more` is true: the URL of the next page, `<https://api1.videonest.co/v1/videos?limit=50&cursor=...>; rel=\"next\"`.","schema":{"type":"string"}}}},"400":{"description":"The request has an invalid or missing parameter (`parameter_invalid`), or a `cursor` that does not belong to this query (`cursor_invalid`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"The API key is missing, invalid, revoked, or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The key lacks the required scope (`missing_scope`) or may not be used from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such object, or the key cannot see it (`resource_missing`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests. Wait for `Retry-After` seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"x-required-scopes":["read_videos"]}},"/videos/{video_id}":{"get":{"tags":["Videos"],"summary":"Retrieve a video","description":"Returns one video. A video the key cannot reach returns 404.\n\nRequired scope: `read_videos`.","operationId":"videos.retrieve","security":[{"ApiKey":["read_videos"]}],"parameters":[{"name":"video_id","in":"path","required":true,"schema":{"type":"string","title":"Video Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Video"}}}},"400":{"description":"The request has an invalid or missing parameter (`parameter_invalid`), or a `cursor` that does not belong to this query (`cursor_invalid`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"The API key is missing, invalid, revoked, or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The key lacks the required scope (`missing_scope`) or may not be used from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such object, or the key cannot see it (`resource_missing`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests. Wait for `Retry-After` seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"x-required-scopes":["read_videos"]},"patch":{"tags":["Videos"],"summary":"Update a video","description":"Changes the video's `title`, `description`, `tags`, or `evergreen_eligible`. Send only the fields to change. `tags` replaces the whole list. An `evergreen_eligible` value set here is kept: automatic evergreen checks no longer change it. Setting the value the video already has changes nothing. No other video field can be changed through the API.\n\nRequired scope: `write_videos`.","operationId":"videos.update","security":[{"ApiKey":["write_videos"]}],"parameters":[{"name":"video_id","in":"path","required":true,"schema":{"type":"string","title":"Video Id"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","minLength":1,"maxLength":255},{"type":"null"}],"description":"Makes the request safe to repeat. A repeat with the same key and body within 24 hours returns the first response and sets `Idempotent-Replayed: true`. The same key with a different body is a 400; a repeat while the first request runs is a 409.","title":"Idempotency-Key"},"description":"Makes the request safe to repeat. A repeat with the same key and body within 24 hours returns the first response and sets `Idempotent-Replayed: true`. The same key with a different body is a 400; a repeat while the first request runs is a 409."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VideoUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Video"}}}},"400":{"description":"The request has an invalid or missing parameter (`parameter_invalid`), or a `cursor` that does not belong to this query (`cursor_invalid`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"The API key is missing, invalid, revoked, or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The key lacks the required scope (`missing_scope`) or may not be used from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such object, or the key cannot see it (`resource_missing`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"A request with this Idempotency-Key is still running, or upload completion has already started.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"The request body is larger than 1 MiB (`request_too_large`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests. Wait for `Retry-After` seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"x-required-scopes":["write_videos"]}},"/videos/{video_id}/captions":{"get":{"tags":["Videos"],"summary":"List a video's caption tracks","description":"Returns the video's caption and chapter tracks as a list of WebVTT files. Each track carries the file's URL, not its contents. The URL is null unless the video's `access_mode` is `public`: the files are not access controlled, so their addresses are not given for email, password or paid videos. A video with no tracks returns an empty list.\n\nRequired scope: `read_captions`.","operationId":"videos.captions.list","security":[{"ApiKey":["read_captions"]}],"parameters":[{"name":"video_id","in":"path","required":true,"schema":{"type":"string","title":"Video Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CaptionTrackList"}}}},"400":{"description":"The request has an invalid or missing parameter (`parameter_invalid`), or a `cursor` that does not belong to this query (`cursor_invalid`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"The API key is missing, invalid, revoked, or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The key lacks the required scope (`missing_scope`) or may not be used from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such object, or the key cannot see it (`resource_missing`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests. Wait for `Retry-After` seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"x-required-scopes":["read_captions"]}},"/uploads":{"post":{"tags":["Uploads"],"summary":"Create a video upload","description":"Creates a 24-hour upload bound to this API key. PUT each chunk to the corresponding presigned URL, then complete the upload. Metadata is fixed at creation.\n\nRequired scope: `write_videos`.","operationId":"uploads.create","security":[{"ApiKey":["write_videos"]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","minLength":1,"maxLength":255},{"type":"null"}],"description":"Makes the request safe to repeat. A repeat with the same key and body within 24 hours returns the first response and sets `Idempotent-Replayed: true`. The same key with a different body is a 400; a repeat while the first request runs is a 409.","title":"Idempotency-Key"},"description":"Makes the request safe to repeat. A repeat with the same key and body within 24 hours returns the first response and sets `Idempotent-Replayed: true`. The same key with a different body is a 400; a repeat while the first request runs is a 409."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Upload"}}}},"400":{"description":"The request has an invalid or missing parameter (`parameter_invalid`), or a `cursor` that does not belong to this query (`cursor_invalid`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"The API key is missing, invalid, revoked, or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The key lacks the required scope (`missing_scope`) or may not be used from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such object, or the key cannot see it (`resource_missing`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"A request with this Idempotency-Key is still running, or upload completion has already started.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"The request body is larger than 1 MiB (`request_too_large`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests. Wait for `Retry-After` seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Upload storage or session persistence is unavailable (`upload_unavailable`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"x-required-scopes":["write_videos"]}},"/uploads/{upload_id}":{"get":{"tags":["Uploads"],"summary":"Retrieve an upload","description":"Returns an unexpired upload created by this API key. Channel access is checked again on every call.\n\nRequired scope: `read_videos`.","operationId":"uploads.retrieve","security":[{"ApiKey":["read_videos"]}],"parameters":[{"name":"upload_id","in":"path","required":true,"schema":{"type":"string","title":"Upload Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Upload"}}}},"401":{"description":"The API key is missing, invalid, revoked, or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The key lacks the required scope (`missing_scope`) or may not be used from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such object, or the key cannot see it (`resource_missing`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests. Wait for `Retry-After` seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Upload storage or session persistence is unavailable (`upload_unavailable`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"x-required-scopes":["read_videos"]}},"/uploads/{upload_id}/complete":{"post":{"tags":["Uploads"],"summary":"Complete a video upload","description":"Completes all parts in consecutive part-number order and creates a video. Retrying a successful completion returns the same video. An uncertain or failed completion requires support; it is never repeated automatically.\n\nRequired scope: `write_videos`.","operationId":"uploads.complete","security":[{"ApiKey":["write_videos"]}],"parameters":[{"name":"upload_id","in":"path","required":true,"schema":{"type":"string","title":"Upload Id"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","minLength":1,"maxLength":255},{"type":"null"}],"description":"Makes the request safe to repeat. A repeat with the same key and body within 24 hours returns the first response and sets `Idempotent-Replayed: true`. The same key with a different body is a 400; a repeat while the first request runs is a 409.","title":"Idempotency-Key"},"description":"Makes the request safe to repeat. A repeat with the same key and body within 24 hours returns the first response and sets `Idempotent-Replayed: true`. The same key with a different body is a 400; a repeat while the first request runs is a 409."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadComplete"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Video"}}}},"400":{"description":"The request has an invalid or missing parameter (`parameter_invalid`), or a `cursor` that does not belong to this query (`cursor_invalid`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"The API key is missing, invalid, revoked, or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The key lacks the required scope (`missing_scope`) or may not be used from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such object, or the key cannot see it (`resource_missing`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"A request with this Idempotency-Key is still running, or upload completion has already started.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"The request body is larger than 1 MiB (`request_too_large`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests. Wait for `Retry-After` seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Upload storage or session persistence is unavailable (`upload_unavailable`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"x-required-scopes":["write_videos"]}},"/videos/bulk_update":{"post":{"tags":["Videos"],"summary":"Update evergreen_eligible on many videos","description":"Sets `evergreen_eligible` on 1 to 100 videos in one call. A valid call always returns 200 with one `video_update_result` per video, in request order. A video that cannot be changed has status `failed` and an `error_code`: `resource_missing` or `insufficient_role`. The others are still applied. A video that already has the value is `unchanged` and is not written. A value set here is kept: automatic evergreen checks no longer change it. The call is all-or-nothing against a database error (a 5xx). A bad id, a repeated id, an unknown field, a value that is not true or false, or more than 100 videos is a 400 for the whole call. To work through a library, list `/videos?evergreen_eligible=false&limit=100`, send that page here, then follow `next_cursor`. Bulk updates have their own, lower rate limit.\n\nRequired scope: `write_videos`.","operationId":"videos.bulk_update","security":[{"ApiKey":["write_videos"]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","minLength":1,"maxLength":255},{"type":"null"}],"description":"Makes the request safe to repeat. A repeat with the same key and body within 24 hours returns the first response and sets `Idempotent-Replayed: true`. The same key with a different body is a 400; a repeat while the first request runs is a 409.","title":"Idempotency-Key"},"description":"Makes the request safe to repeat. A repeat with the same key and body within 24 hours returns the first response and sets `Idempotent-Replayed: true`. The same key with a different body is a 400; a repeat while the first request runs is a 409."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkVideoUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VideoUpdateResultList"}}}},"400":{"description":"The request has an invalid or missing parameter (`parameter_invalid`), or a `cursor` that does not belong to this query (`cursor_invalid`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"The API key is missing, invalid, revoked, or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The key lacks the required scope (`missing_scope`) or may not be used from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"A request with this Idempotency-Key is still running, or upload completion has already started.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"The request body is larger than 1 MiB (`request_too_large`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests. Wait for `Retry-After` seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"x-required-scopes":["write_videos"]}},"/videos/{video_id}/thumbnail":{"post":{"tags":["Videos"],"summary":"Replace a video's thumbnail","description":"Upload a JPEG, PNG, or WebP image in the multipart `thumbnail` field. The complete multipart request must be at most 1 MiB, including its headers and boundaries. Images must contain at most 25 million pixels. The thumbnail is converted to WebP and downscaled to at most 480 pixels wide, preserving its aspect ratio.\n\nRequired scope: `write_videos`.","operationId":"videos.thumbnail.update","security":[{"ApiKey":["write_videos"]}],"parameters":[{"name":"video_id","in":"path","required":true,"schema":{"type":"string","title":"Video Id"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","minLength":1,"maxLength":255},{"type":"null"}],"description":"Makes the request safe to repeat. A repeat with the same key and body within 24 hours returns the first response and sets `Idempotent-Replayed: true`. The same key with a different body is a 400; a repeat while the first request runs is a 409.","title":"Idempotency-Key"},"description":"Makes the request safe to repeat. A repeat with the same key and body within 24 hours returns the first response and sets `Idempotent-Replayed: true`. The same key with a different body is a 400; a repeat while the first request runs is a 409."}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/update"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Video"}}}},"400":{"description":"The request has an invalid or missing parameter (`parameter_invalid`), or a `cursor` that does not belong to this query (`cursor_invalid`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"The API key is missing, invalid, revoked, or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The key lacks the required scope (`missing_scope`) or may not be used from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such object, or the key cannot see it (`resource_missing`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"A request with this Idempotency-Key is still running, or upload completion has already started.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"The request body is larger than 1 MiB (`request_too_large`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests. Wait for `Retry-After` seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Thumbnail storage is temporarily unavailable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"x-required-scopes":["write_videos"]}},"/feeds":{"get":{"tags":["Feeds"],"summary":"List feeds","description":"Returns feeds of the channels the key can reach, newest first. Feeds are the channel feeds (MRSS, podcast, and video) a channel publishes. Reading them needs the owner to hold the feeds capability on the channel; roles without it (such as Editor) see no feeds.\n\nRequired scope: `read_feeds`.","operationId":"feeds.list","security":[{"ApiKey":["read_feeds"]}],"parameters":[{"name":"channel","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Only feeds of this channel, for example `chn_4412`.","title":"Channel"},"description":"Only feeds of this channel, for example `chn_4412`."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Number of objects to return, between 1 and 100.","default":50,"title":"Limit"},"description":"Number of objects to return, between 1 and 100."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"The `next_cursor` of the previous page. Send the same filters as the request that returned it.","title":"Cursor"},"description":"The `next_cursor` of the previous page. Send the same filters as the request that returned it."}],"responses":{"200":{"description":"A page of results.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedList"}}},"headers":{"Link":{"description":"Present when `has_more` is true: the URL of the next page, `<https://api1.videonest.co/v1/videos?limit=50&cursor=...>; rel=\"next\"`.","schema":{"type":"string"}}}},"400":{"description":"The request has an invalid or missing parameter (`parameter_invalid`), or a `cursor` that does not belong to this query (`cursor_invalid`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"The API key is missing, invalid, revoked, or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The key lacks the required scope (`missing_scope`) or may not be used from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such object, or the key cannot see it (`resource_missing`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests. Wait for `Retry-After` seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"x-required-scopes":["read_feeds"]}},"/feeds/{feed_id}":{"get":{"tags":["Feeds"],"summary":"Retrieve a feed","description":"Returns one feed. A feed the key cannot reach returns 404. Feeds are the channel feeds (MRSS, podcast, and video) a channel publishes. Reading them needs the owner to hold the feeds capability on the channel; roles without it (such as Editor) see no feeds.\n\nRequired scope: `read_feeds`.","operationId":"feeds.retrieve","security":[{"ApiKey":["read_feeds"]}],"parameters":[{"name":"feed_id","in":"path","required":true,"schema":{"type":"string","title":"Feed Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Feed"}}}},"400":{"description":"The request has an invalid or missing parameter (`parameter_invalid`), or a `cursor` that does not belong to this query (`cursor_invalid`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"The API key is missing, invalid, revoked, or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The key lacks the required scope (`missing_scope`) or may not be used from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such object, or the key cannot see it (`resource_missing`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests. Wait for `Retry-After` seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"x-required-scopes":["read_feeds"]}},"/analytics/views":{"get":{"tags":["Analytics"],"summary":"List daily views for a channel","description":"Returns one `daily_views` object per UTC day for one channel, oldest day first, with zeros filled in. `date_min` and `date_max` are inclusive dates (`2026-09-01`) and cover at most 90 days; they default to the last 30 days. The list is never paged. Analytics requests have a lower rate limit than other endpoints.\n\nRequired scope: `read_analytics`.","operationId":"analytics.views","security":[{"ApiKey":["read_analytics"]}],"parameters":[{"name":"channel","in":"query","required":true,"schema":{"type":"string","description":"The channel to report on, for example `chn_4412`.","title":"Channel"},"description":"The channel to report on, for example `chn_4412`."},{"name":"date_min","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"description":"First day included (`YYYY-MM-DD`, UTC).","title":"Date Min"},"description":"First day included (`YYYY-MM-DD`, UTC)."},{"name":"date_max","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"description":"Last day included (`YYYY-MM-DD`, UTC).","title":"Date Max"},"description":"Last day included (`YYYY-MM-DD`, UTC)."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DailyViewsList"}}}},"400":{"description":"The request has an invalid or missing parameter (`parameter_invalid`), or a `cursor` that does not belong to this query (`cursor_invalid`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"The API key is missing, invalid, revoked, or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The key lacks the required scope (`missing_scope`) or may not be used from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such object, or the key cannot see it (`resource_missing`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests. Wait for `Retry-After` seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"x-required-scopes":["read_analytics"]}},"/api_keys/current":{"get":{"tags":["API keys"],"summary":"Retrieve the current API key","description":"Describes the key that signed this request: its scopes, workspace, channel limits, and expiry. The secret is never returned. Agents can call this first to learn what they may do.\n\nRequired scope: none. Any valid API key may call this.","operationId":"api_keys.current","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyInfo"}}}},"401":{"description":"The API key is missing, invalid, revoked, or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The key lacks the required scope (`missing_scope`) or may not be used from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such object, or the key cannot see it (`resource_missing`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests. Wait for `Retry-After` seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"ApiKey":[]}],"x-required-scopes":[]}}},"components":{"schemas":{"ApiKeyInfo":{"properties":{"id":{"type":"string","title":"Id","description":"Key id, prefixed `key_`. Not the secret."},"object":{"type":"string","const":"api_key","title":"Object","default":"api_key"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"last4":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last4","description":"Last four characters of the key."},"scopes":{"items":{"type":"string"},"type":"array","title":"Scopes","description":"Scopes the key holds, implied read scopes included."},"workspace":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Workspace","description":"Workspace id, if the key is tied to one."},"channels":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Channels","description":"Channel ids the key is limited to, or null for every channel its owner can reach."},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At"},"agent":{"type":"boolean","title":"Agent","description":"True for keys issued to an AI agent."}},"type":"object","required":["id","created_at","scopes","agent"],"title":"ApiKeyInfo","examples":[{"agent":false,"channels":["chn_4412"],"created_at":"2026-09-15T10:00:00Z","id":"key_cm7k2p9q1","last4":"1F6y","name":"Nightly sync","object":"api_key","scopes":["read_channels","read_videos","write_videos"],"workspace":"ws_cm1x2y3z4"}]},"BulkVideoUpdate":{"properties":{"updates":{"items":{"$ref":"#/components/schemas/BulkVideoUpdateItem"},"type":"array","maxItems":100,"minItems":1,"title":"Updates","description":"1 to 100 videos. Each video may appear once."}},"additionalProperties":false,"type":"object","required":["updates"],"title":"BulkVideoUpdate","description":"Evergreen changes for up to 100 videos, applied together.","examples":[{"updates":[{"evergreen_eligible":true,"id":"vid_981234"},{"evergreen_eligible":false,"id":"vid_981235"}]}]},"BulkVideoUpdateItem":{"properties":{"id":{"type":"string","title":"Id","description":"Video id, prefixed `vid_`."},"evergreen_eligible":{"type":"boolean","title":"Evergreen Eligible","description":"True or false. Not nullable."}},"additionalProperties":false,"type":"object","required":["id","evergreen_eligible"],"title":"BulkVideoUpdateItem","description":"One video in a bulk update, and the evergreen value to give it."},"CaptionTrack":{"properties":{"id":{"type":"string","title":"Id","description":"Track id, prefixed `cap_`."},"object":{"type":"string","const":"caption_track","title":"Object","default":"caption_track"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"video":{"type":"string","title":"Video","description":"Video id, prefixed `vid_`."},"kind":{"type":"string","enum":["captions","transcript","chapters"],"title":"Kind","description":"`captions` is the creator's caption track. `transcript` is the auto-generated transcript, listed only when the video has no caption track. `chapters` is the chapter track."},"format":{"type":"string","const":"vtt","title":"Format","default":"vtt"},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url","description":"URL of the WebVTT file. Null unless the video's `access_mode` is `public`."},"file_size":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"File Size","description":"Size in bytes."}},"type":"object","required":["id","video","kind"],"title":"CaptionTrack","examples":[{"created_at":"2026-09-02T08:10:00Z","file_size":20480,"format":"vtt","id":"cap_5521","kind":"captions","object":"caption_track","url":"https://cdn.videonest.co/gamma/captions/981234-1788336600000.vtt","video":"vid_981234"}]},"CaptionTrackList":{"properties":{"object":{"type":"string","const":"list","title":"Object","default":"list"},"has_more":{"type":"boolean","title":"Has More","description":"True when more objects exist beyond this page."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Send this as `cursor` to get the next page, with the same filters. Null when `has_more` is false."},"data":{"items":{"$ref":"#/components/schemas/CaptionTrack"},"type":"array","title":"Data"}},"type":"object","required":["has_more","next_cursor","data"],"title":"CaptionTrackList"},"Channel":{"properties":{"id":{"type":"string","title":"Id","description":"Channel id, prefixed `chn_`."},"object":{"type":"string","const":"channel","title":"Object","default":"channel"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"},"title":{"type":"string","title":"Title","description":"The channel name."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"language":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Language"},"subdomain":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subdomain"},"custom_domain":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Domain"},"logo_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Logo Url"},"banner_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Banner Url"},"workspace":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Workspace","description":"Workspace id, prefixed `ws_`."}},"type":"object","required":["id","created_at","title"],"title":"Channel","examples":[{"created_at":"2026-01-14T09:45:00Z","description":"Documentaries and behind-the-scenes films.","id":"chn_4412","language":"english","logo_url":"https://cdn.videonest.co/channels/4412/logo.png","object":"channel","subdomain":"acme","title":"Acme Originals","updated_at":"2026-09-01T16:20:11Z","workspace":"ws_cm1x2y3z4"}]},"ChannelList":{"properties":{"object":{"type":"string","const":"list","title":"Object","default":"list"},"has_more":{"type":"boolean","title":"Has More","description":"True when more objects exist beyond this page."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Send this as `cursor` to get the next page, with the same filters. Null when `has_more` is false."},"data":{"items":{"$ref":"#/components/schemas/Channel"},"type":"array","title":"Data"}},"type":"object","required":["has_more","next_cursor","data"],"title":"ChannelList"},"ChannelUpdate":{"properties":{"title":{"anyOf":[{"type":"string","maxLength":255,"minLength":1},{"type":"null"}],"title":"Title","description":"New channel name."},"description":{"anyOf":[{"type":"string","maxLength":5000},{"type":"null"}],"title":"Description","description":"New description. Send null to clear it."}},"additionalProperties":false,"type":"object","title":"ChannelUpdate","description":"Fields a key may change on a channel. Anything else is rejected.","examples":[{"description":"Documentaries and films."}]},"DailyViews":{"properties":{"object":{"type":"string","const":"daily_views","title":"Object","default":"daily_views"},"channel":{"type":"string","title":"Channel","description":"Channel id, prefixed `chn_`."},"date":{"type":"string","format":"date","title":"Date","description":"The UTC day, `YYYY-MM-DD`."},"views":{"type":"integer","title":"Views","description":"Views on that day. Zero when there were none."}},"type":"object","required":["channel","date","views"],"title":"DailyViews","examples":[{"channel":"chn_4412","date":"2026-09-01","object":"daily_views","views":400}]},"DailyViewsList":{"properties":{"object":{"type":"string","const":"list","title":"Object","default":"list"},"has_more":{"type":"boolean","title":"Has More","description":"True when more objects exist beyond this page."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Send this as `cursor` to get the next page, with the same filters. Null when `has_more` is false."},"data":{"items":{"$ref":"#/components/schemas/DailyViews"},"type":"array","title":"Data"}},"type":"object","required":["has_more","next_cursor","data"],"title":"DailyViewsList"},"ErrorDetail":{"properties":{"type":{"type":"string","enum":["invalid_request_error","authentication_error","permission_error","rate_limit_error","idempotency_error","api_error"],"title":"Type"},"code":{"type":"string","title":"Code","description":"Stable machine-readable code, for example `missing_scope`."},"message":{"type":"string","title":"Message","description":"Human-readable explanation. Do not parse it."},"param":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Param","description":"The parameter at fault, if any."},"doc_url":{"type":"string","title":"Doc Url","description":"Page that explains this code."},"request_id":{"type":"string","title":"Request Id","description":"Quote this when you contact support."},"required_scope":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Required Scope","description":"On `missing_scope`: the scope the key lacks."}},"type":"object","required":["type","code","message","doc_url","request_id"],"title":"ErrorDetail"},"ErrorResponse":{"properties":{"error":{"$ref":"#/components/schemas/ErrorDetail"}},"type":"object","required":["error"],"title":"ErrorResponse","examples":[{"error":{"code":"missing_scope","doc_url":"https://docs.videonest.co/api/errors#missing_scope","message":"This API key lacks the required scope: write_videos.","request_id":"req_4fT9kQw2LmX8sB1cVn7ZyPdA","required_scope":"write_videos","type":"permission_error"}}]},"Feed":{"properties":{"id":{"type":"string","title":"Id","description":"Feed id, prefixed `feed_`. Names a channel feed."},"object":{"type":"string","const":"feed","title":"Object","default":"feed"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"name":{"type":"string","title":"Name"},"channel":{"type":"string","title":"Channel","description":"Channel id, prefixed `chn_`."},"type":{"type":"string","title":"Type","description":"What the feed carries, for example `video` or `podcast`."},"feed_type":{"type":"string","title":"Feed Type","description":"How the feed fills: `static`, `dynamic`, and so on."},"slug":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Slug","description":"The feed's short URL name."},"public":{"type":"boolean","title":"Public"},"orientation":{"type":"string","title":"Orientation","description":"`both`, `landscape` or `portrait`."},"artwork_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Artwork Url"}},"type":"object","required":["id","created_at","name","channel","type","feed_type","public","orientation"],"title":"Feed","examples":[{"channel":"chn_4412","created_at":"2026-03-03T11:00:00Z","feed_type":"dynamic","id":"feed_7730","name":"Acme MRSS","object":"feed","orientation":"both","public":true,"slug":"acme-mrss","type":"video"}]},"FeedList":{"properties":{"object":{"type":"string","const":"list","title":"Object","default":"list"},"has_more":{"type":"boolean","title":"Has More","description":"True when more objects exist beyond this page."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Send this as `cursor` to get the next page, with the same filters. Null when `has_more` is false."},"data":{"items":{"$ref":"#/components/schemas/Feed"},"type":"array","title":"Data"}},"type":"object","required":["has_more","next_cursor","data"],"title":"FeedList"},"Upload":{"properties":{"id":{"type":"string","title":"Id"},"object":{"type":"string","const":"upload","title":"Object","default":"upload"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"expires_at":{"type":"string","format":"date-time","title":"Expires At"},"channel":{"type":"string","title":"Channel"},"filename":{"type":"string","title":"Filename"},"file_size":{"type":"integer","title":"File Size"},"content_type":{"type":"string","title":"Content Type"},"chunk_size":{"type":"integer","title":"Chunk Size"},"presigned_urls":{"items":{"type":"string"},"type":"array","title":"Presigned Urls"},"status":{"type":"string","enum":["pending","completing","completed","failed"],"title":"Status"}},"type":"object","required":["id","created_at","expires_at","channel","filename","file_size","content_type","chunk_size","presigned_urls","status"],"title":"Upload"},"UploadComplete":{"properties":{"parts":{"items":{"$ref":"#/components/schemas/UploadPart"},"type":"array","maxItems":10000,"minItems":1,"title":"Parts"}},"additionalProperties":false,"type":"object","required":["parts"],"title":"UploadComplete"},"UploadCreate":{"properties":{"channel":{"type":"string","title":"Channel"},"filename":{"type":"string","maxLength":255,"minLength":1,"title":"Filename"},"file_size":{"type":"integer","maximum":5497558138880.0,"exclusiveMinimum":0.0,"title":"File Size"},"content_type":{"type":"string","maxLength":100,"pattern":"^video/[a-zA-Z0-9.+-]+$","title":"Content Type"},"title":{"type":"string","maxLength":255,"minLength":1,"title":"Title"},"description":{"type":"string","maxLength":50000,"title":"Description","default":""},"tags":{"items":{"type":"string","maxLength":100,"minLength":1},"type":"array","maxItems":50,"title":"Tags"}},"additionalProperties":false,"type":"object","required":["channel","filename","file_size","content_type","title"],"title":"UploadCreate"},"UploadPart":{"properties":{"part_number":{"type":"integer","maximum":10000.0,"minimum":1.0,"title":"Part Number"},"etag":{"type":"string","maxLength":255,"minLength":1,"title":"Etag"}},"additionalProperties":false,"type":"object","required":["part_number","etag"],"title":"UploadPart"},"Video":{"properties":{"id":{"type":"string","title":"Id","description":"Video id, prefixed `vid_`."},"object":{"type":"string","const":"video","title":"Object","default":"video"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When VideoNest ingested the video. Falls back to `published_at`."},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"},"title":{"type":"string","title":"Title"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Null when the video has no description."},"tags":{"items":{"type":"string"},"type":"array","title":"Tags"},"channel":{"type":"string","title":"Channel","description":"Channel id, prefixed `chn_`."},"duration":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Duration","description":"Length in seconds."},"thumbnail_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Thumbnail Url"},"published_at":{"type":"string","format":"date-time","title":"Published At"},"visibility":{"type":"string","enum":["visible","hidden"],"title":"Visibility"},"access_mode":{"type":"string","enum":["public","email","password","paid"],"title":"Access Mode","description":"Who may watch: `public`, `email`, `password` or `paid`."},"view_count":{"type":"integer","title":"View Count"},"source_platform":{"type":"string","title":"Source Platform"},"evergreen_eligible":{"type":"boolean","title":"Evergreen Eligible","description":"Whether the video may be used as evergreen content in looping channel feeds. Always true or false: a video never marked reads as false."}},"type":"object","required":["id","created_at","title","description","tags","channel","published_at","visibility","access_mode","view_count","source_platform","evergreen_eligible"],"title":"Video","examples":[{"access_mode":"public","channel":"chn_4412","created_at":"2026-09-02T08:00:14Z","description":"How the bridge went up in 14 months.","duration":1325,"evergreen_eligible":true,"id":"vid_981234","object":"video","published_at":"2026-09-01T12:00:00Z","source_platform":"youtube","tags":["engineering","documentary"],"thumbnail_url":"https://cdn.videonest.co/videos/981234/thumb.jpg","title":"Building the Harbor Bridge","updated_at":"2026-09-02T08:05:41Z","view_count":18204,"visibility":"visible"}]},"VideoList":{"properties":{"object":{"type":"string","const":"list","title":"Object","default":"list"},"has_more":{"type":"boolean","title":"Has More","description":"True when more objects exist beyond this page."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Send this as `cursor` to get the next page, with the same filters. Null when `has_more` is false."},"data":{"items":{"$ref":"#/components/schemas/Video"},"type":"array","title":"Data"}},"type":"object","required":["has_more","next_cursor","data"],"title":"VideoList"},"VideoUpdate":{"properties":{"title":{"anyOf":[{"type":"string","maxLength":255,"minLength":1},{"type":"null"}],"title":"Title","description":"New title."},"description":{"anyOf":[{"type":"string","maxLength":50000},{"type":"null"}],"title":"Description","description":"New description. Send null to clear it."},"tags":{"anyOf":[{"items":{"type":"string","maxLength":100,"minLength":1},"type":"array","maxItems":50},{"type":"null"}],"title":"Tags","description":"Replaces the video's tags. At most 50."},"evergreen_eligible":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Evergreen Eligible","description":"Mark the video eligible (true) or not (false) for evergreen looping. A value set here is kept: automatic checks no longer change it. Not nullable."}},"additionalProperties":false,"type":"object","title":"VideoUpdate","description":"Fields a key may change on a video. Anything else is rejected.","examples":[{"tags":["engineering"],"title":"Building the Harbor Bridge"}]},"VideoUpdateResult":{"properties":{"object":{"type":"string","const":"video_update_result","title":"Object","default":"video_update_result"},"id":{"type":"string","title":"Id","description":"The video id from the request, prefixed `vid_`."},"status":{"type":"string","enum":["updated","unchanged","failed"],"title":"Status","description":"`updated`: the value changed. `unchanged`: the video already had it, so nothing was written. `failed`: see `error_code`."},"evergreen_eligible":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Evergreen Eligible","description":"The video's value after the call. Null when the update `failed`."},"error_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error Code","description":"On `failed`: `resource_missing` (no such video, or the key cannot reach it) or `insufficient_role` (the key's owner may view the video but not edit it). Otherwise null."},"error_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error Message","description":"On `failed`: a sentence that explains it. Otherwise null."}},"type":"object","required":["id","status","evergreen_eligible","error_code","error_message"],"title":"VideoUpdateResult","examples":[{"evergreen_eligible":true,"id":"vid_981234","object":"video_update_result","status":"updated"}]},"VideoUpdateResultList":{"properties":{"object":{"type":"string","const":"list","title":"Object","default":"list"},"has_more":{"type":"boolean","title":"Has More","description":"True when more objects exist beyond this page."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Send this as `cursor` to get the next page, with the same filters. Null when `has_more` is false."},"data":{"items":{"$ref":"#/components/schemas/VideoUpdateResult"},"type":"array","title":"Data"}},"type":"object","required":["has_more","next_cursor","data"],"title":"VideoUpdateResultList"},"Workspace":{"properties":{"id":{"type":"string","title":"Id","description":"Workspace id, prefixed `ws_`."},"object":{"type":"string","const":"workspace","title":"Object","default":"workspace"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"name":{"type":"string","title":"Name"}},"type":"object","required":["id","created_at","name"],"title":"Workspace","examples":[{"created_at":"2026-01-14T09:30:00Z","id":"ws_cm1x2y3z4","name":"Acme Media","object":"workspace"}]},"update":{"properties":{"thumbnail":{"type":"string","contentMediaType":"application/octet-stream","title":"Thumbnail"}},"type":"object","required":["thumbnail"],"title":"Body_videos.thumbnail.update"}},"securitySchemes":{"ApiKey":{"type":"http","description":"Send your API key as `Authorization: Bearer vn_live_...`. Create keys in the VideoNest dashboard. Keys are secret: use them from a server, never from a browser.","scheme":"bearer","bearerFormat":"vn_live_<key>"}}},"tags":[{"name":"Workspace","description":"The workspace a key belongs to."},{"name":"Channels","description":"Channels the key can reach."},{"name":"Videos","description":"Videos, and their caption and chapter tracks."},{"name":"Uploads","description":"Upload videos directly to storage with scoped API keys."},{"name":"Feeds","description":"Channel distribution feeds (MRSS, podcast, video)."},{"name":"Analytics","description":"Views over time."},{"name":"API keys","description":"Introspect the key making the request."}]}