# Video Channels

> Create branded video channel pages, add and reorder the videos they list, publish them for sharing, and retrieve the shareable URL and embed code through the REST API.

Source: https://docs.oursprivacy.com/docs/platform-api/video-channels

A video channel is a branded, shareable page that lists an ordered set of your [videos](https://docs.oursprivacy.com/docs/platform-api/videos). Create the channel, add videos to it, set its branding, then publish it to get a shareable URL and paste-ready embed code.

## Publishing

New channels start unpublished, so the page is not reachable until you send `isPublished: true` on `PATCH /rest/v1/video-channels/{id}`. Publishing renders the page from the channel's current videos and branding, and every later change to the videos or branding updates the published page. Sending `isPublished: false` takes the page offline.

Because a published channel page is public and unauthenticated, do not add videos whose titles, descriptions, or transcripts contain protected health information (PHI) or other confidential information.

## Videos in a channel

Videos are attached through the channel's `media` sub-resource rather than a field on the channel, because one video can appear in several channels.

* `GET /rest/v1/video-channels/{id}/media` returns the channel's full video list in display order.
* `POST /rest/v1/video-channels/{id}/media` adds a video. Omit `position` to append it to the end. Calling it again for a video already in the channel updates its position instead of adding a duplicate.
* `DELETE /rest/v1/video-channels/{id}/media?mediaId=...` removes one video from this channel. The video itself is not deleted and stays in any other channel it belongs to. This call is idempotent.
* `POST /rest/v1/video-channels/{id}/reorder` sets the display order. It takes every video id currently in the channel, in display order (index 0 appears first).

Deleting a channel takes its page offline and leaves the videos it listed in your library.

## Branding and embedding

`PATCH /rest/v1/video-channels/{id}` sets `description`, `brandColor`, `footerText`, and `logoMediaId`. `logoMediaId` must reference an image in your media library; send `null` to clear it.

`GET /rest/v1/video-channels/{id}` returns `resolvedValues` with the channel's video count, the shareable page URL (`embedUrl`), and the HTML embed snippet (`embedCode`).

## GET /rest/v1/video-channels

List video channels for the account, sorted by name. Supports cursor pagination via `limit` and `cursor`; the limit clamp is 1000 so a single request can return the full set. Entries omit `resolvedValues` — fetch a channel by id for its video count and embed output. Requires API-key scope or current OAuth user permission: videoChannel:list

Request URL: `GET https://app.oursprivacy.com/rest/v1/video-channels`

Authentication: apiKey or oauth2.

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `limit` | query | integer \| null | No | Maximum number of channels to return. Defaults to 25; values below 1 are clamped to 1 and values above 1000 are clamped to 1000. |
| `cursor` | query | string | No | Opaque pagination cursor from pagination.nextCursor in the previous response. Do not decode or modify it. Malformed cursors return 400 Bad Request. Opaque pagination cursor from pagination.nextCursor in the previous response. Do not decode or modify it. Malformed cursors return 400 Bad Request. |

### Responses

- `200`: Paginated list of video channels
- `400`: Bad Request
- `401`: Unauthorized — missing, invalid, or expired API key or OAuth access token
- `403`: Forbidden — credential does not have the required current Ours permission
- `404`: Not Found
- `500`: Internal Server Error

#### `200` response body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `entities` | object[] | Yes |  |
| `entities[].id` | string | Yes |  |
| `entities[].accountId` | string | Yes |  |
| `entities[].name` | string | Yes |  |
| `entities[].description` | string \| null | No |  |
| `entities[].brandColor` | string \| null | No |  |
| `entities[].logoMediaId` | string \| null | No |  |
| `entities[].footerText` | string \| null | No |  |
| `entities[].isPublished` | boolean \| null | No |  |
| `entities[].createdAt` | string \| null | No |  |
| `entities[].updatedAt` | string \| null | No |  |
| `pagination` | object | Yes |  |
| `pagination.nextCursor` | string \| null | No |  |
| `pagination.hasMore` | boolean | Yes |  |

Full schema: [OpenAPI specification](https://docs.oursprivacy.com/openapi-platform.json).

## POST /rest/v1/video-channels

Create a video channel. Only `name` is accepted here; set branding and publish it with PATCH, and add videos with `POST /rest/v1/video-channels/{id}/media`. New channels start unpublished, so the page is not reachable until you send `isPublished: true`. Requires API-key scope or current OAuth user permission: videoChannel:create

Request URL: `POST https://app.oursprivacy.com/rest/v1/video-channels`

Authentication: apiKey or oauth2.

### Request body (`application/json`, required)

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | Yes | Channel name. Case-insensitively unique within the account. |

### Responses

- `200`: Created video channel
- `400`: Bad Request
- `401`: Unauthorized — missing, invalid, or expired API key or OAuth access token
- `403`: Forbidden — credential does not have the required current Ours permission
- `404`: Not Found
- `409`: Conflict — a channel with the same name (case-insensitive) already exists in this account.
- `500`: Internal Server Error

#### `200` response body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | Yes |  |
| `accountId` | string | Yes |  |
| `name` | string | Yes |  |
| `description` | string \| null | No |  |
| `brandColor` | string \| null | No |  |
| `logoMediaId` | string \| null | No |  |
| `footerText` | string \| null | No |  |
| `isPublished` | boolean \| null | No |  |
| `createdAt` | string \| null | No |  |
| `updatedAt` | string \| null | No |  |

Full schema: [OpenAPI specification](https://docs.oursprivacy.com/openapi-platform.json).

## GET /rest/v1/video-channels/{id}

Fetch a channel with its branding, publish state, video count, shareable page URL, and paste-ready embed code. Requires API-key scope or current OAuth user permission: videoChannel:find

Request URL: `GET https://app.oursprivacy.com/rest/v1/video-channels/{id}`

Authentication: apiKey or oauth2.

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | Yes |  |

### Responses

- `200`: Channel details, video count, and embed output
- `400`: Bad Request
- `401`: Unauthorized — missing, invalid, or expired API key or OAuth access token
- `403`: Forbidden — credential does not have the required current Ours permission
- `404`: Not Found
- `500`: Internal Server Error

#### `200` response body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | Yes |  |
| `accountId` | string | Yes |  |
| `name` | string | Yes |  |
| `description` | string \| null | No |  |
| `brandColor` | string \| null | No |  |
| `logoMediaId` | string \| null | No |  |
| `footerText` | string \| null | No |  |
| `isPublished` | boolean \| null | No |  |
| `createdAt` | string \| null | No |  |
| `updatedAt` | string \| null | No |  |
| `resolvedValues` | object \| null | No |  |
| `resolvedValues.mediaCount` | integer | Yes |  |
| `resolvedValues.embedUrl` | string | Yes |  |
| `resolvedValues.embedCode` | string | Yes |  |

Full schema: [OpenAPI specification](https://docs.oursprivacy.com/openapi-platform.json).

## PATCH /rest/v1/video-channels/{id}

Partially update a channel. Only fields included in the body change; send `null` to clear a nullable field. Sending `isPublished: true` makes the channel page reachable and renders it from the current videos and branding; `false` takes it offline. `logoMediaId` must reference an image in your media library. Requires API-key scope or current OAuth user permission: videoChannel:update

Request URL: `PATCH https://app.oursprivacy.com/rest/v1/video-channels/{id}`

Authentication: apiKey or oauth2.

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | Yes |  |

### Request body (`application/json`, required)

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string \| null | No | New channel name. Must stay case-insensitively unique within the account. |
| `description` | string \| null | No |  |
| `brandColor` | string \| null | No | Accent color used on the channel page. Any CSS color string. |
| `logoMediaId` | string \| null | No | Id of an image in your media library to show as the channel logo. Must be an image; send `null` to clear it. |
| `footerText` | string \| null | No |  |
| `isPublished` | boolean \| null | No | Whether the channel page is publicly reachable. Publishing renders the page from the current videos and branding; unpublishing takes it offline. |

### Responses

- `200`: Updated video channel
- `400`: Bad Request
- `401`: Unauthorized — missing, invalid, or expired API key or OAuth access token
- `403`: Forbidden — credential does not have the required current Ours permission
- `404`: Not Found
- `409`: Conflict — a channel with the same name (case-insensitive) already exists in this account.
- `500`: Internal Server Error

#### `200` response body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | Yes |  |
| `accountId` | string | Yes |  |
| `name` | string | Yes |  |
| `description` | string \| null | No |  |
| `brandColor` | string \| null | No |  |
| `logoMediaId` | string \| null | No |  |
| `footerText` | string \| null | No |  |
| `isPublished` | boolean \| null | No |  |
| `createdAt` | string \| null | No |  |
| `updatedAt` | string \| null | No |  |
| `resolvedValues` | object \| null | No |  |
| `resolvedValues.mediaCount` | integer | Yes |  |
| `resolvedValues.embedUrl` | string | Yes |  |
| `resolvedValues.embedCode` | string | Yes |  |

Full schema: [OpenAPI specification](https://docs.oursprivacy.com/openapi-platform.json).

## DELETE /rest/v1/video-channels/{id}

Delete a channel and take its page offline. The videos it listed are not deleted — only their membership in this channel. Requires API-key scope or current OAuth user permission: videoChannel:delete

Request URL: `DELETE https://app.oursprivacy.com/rest/v1/video-channels/{id}`

Authentication: apiKey or oauth2.

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | Yes |  |

### Responses

- `200`: Deleted video channel
- `400`: Bad Request
- `401`: Unauthorized — missing, invalid, or expired API key or OAuth access token
- `403`: Forbidden — credential does not have the required current Ours permission
- `404`: Not Found
- `500`: Internal Server Error

#### `200` response body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | Yes |  |
| `deleted` | boolean | Yes | One of: `true`. |

Full schema: [OpenAPI specification](https://docs.oursprivacy.com/openapi-platform.json).

## GET /rest/v1/video-channels/{id}/media

List the videos in a channel, ordered by their position on the page. Not paginated: a channel holds a bounded set of videos, so the full ordered list is always returned. Videos whose media no longer resolves are omitted rather than returned as broken entries. Requires API-key scope or current OAuth user permission: videoChannel:find

Request URL: `GET https://app.oursprivacy.com/rest/v1/video-channels/{id}/media`

Authentication: apiKey or oauth2.

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | Yes |  |

### Responses

- `200`: The channel's videos in display order
- `400`: Bad Request
- `401`: Unauthorized — missing, invalid, or expired API key or OAuth access token
- `403`: Forbidden — credential does not have the required current Ours permission
- `404`: Not Found
- `500`: Internal Server Error

#### `200` response body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `entities` | object[] | Yes |  |
| `entities[].id` | string | Yes |  |
| `entities[].accountId` | string | Yes |  |
| `entities[].createdAt` | string | Yes |  |
| `entities[].updatedAt` | string \| null | No |  |
| `entities[].type` | string | Yes | One of: `"Video"`. |
| `entities[].name` | string \| null | No |  |
| `entities[].description` | string \| null | No |  |
| `entities[].duration` | number \| null | No |  |
| `entities[].width` | number \| null | No |  |
| `entities[].height` | number \| null | No |  |
| `entities[].hasVideoUpload` | boolean \| null | No |  |
| `entities[].sourceLanguageCode` | string \| null | No |  |
| `entities[].captionTracks` | object[] | Yes |  |
| `entities[].captionTracks[].languageCode` | string | Yes |  |
| `entities[].captionTracks[].label` | string | Yes |  |
| `entities[].captionTracks[].url` | string | Yes |  |
| `entities[].captionTracks[].origin` | string | Yes |  |
| `entities[].captionTracks[].status` | string | Yes |  |
| `entities[].captionTracks[].isMachineTranslated` | boolean | Yes |  |
| `entities[].captionTracks[].humanEditedAt` | string \| null | No |  |
| `entities[].captionsUpdatedAt` | string \| null | No |  |
| `entities[].captionsUpdatedByName` | string \| null | No |  |

Full schema: [OpenAPI specification](https://docs.oursprivacy.com/openapi-platform.json).

## POST /rest/v1/video-channels/{id}/media

Add a video to a channel. Omit `position` to append it to the end. A video can belong to several channels, so adding it here does not remove it from any other. Calling this again for a video already in the channel updates its position instead of adding a duplicate, and keeps its current slot when `position` is omitted. The returned `id` is a composite membership key, not a UUID. Requires API-key scope or current OAuth user permission: videoChannel:update

Request URL: `POST https://app.oursprivacy.com/rest/v1/video-channels/{id}/media`

Authentication: apiKey or oauth2.

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | Yes |  |

### Request body (`application/json`, required)

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `mediaId` | string (uuid) | Yes | Id of the video to add to the channel. Must be a video, not an image. |
| `position` | integer | No | Zero-based slot in the channel order. Omit to append to the end; omitting it on a video that is already in the channel keeps its current slot. |

### Responses

- `200`: The video’s membership in this channel
- `400`: Bad request — `mediaId` refers to an image rather than a video.
- `401`: Unauthorized — missing, invalid, or expired API key or OAuth access token
- `403`: Forbidden — credential does not have the required current Ours permission
- `404`: Not found — the channel or the video does not exist in this account.
- `500`: Internal Server Error

#### `200` response body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | Yes |  |
| `accountId` | string | Yes |  |
| `channelId` | string \| null | No |  |
| `mediaId` | string | Yes |  |
| `position` | number \| null | No |  |
| `createdAt` | string \| null | No |  |
| `updatedAt` | string \| null | No |  |

Full schema: [OpenAPI specification](https://docs.oursprivacy.com/openapi-platform.json).

## DELETE /rest/v1/video-channels/{id}/media

Remove one video from a channel, identified by the `mediaId` query parameter. The video itself is not deleted and stays in any other channel it belongs to. Idempotent — removing a video that is not in the channel succeeds and returns the channel unchanged. Requires API-key scope or current OAuth user permission: videoChannel:update

Request URL: `DELETE https://app.oursprivacy.com/rest/v1/video-channels/{id}/media`

Authentication: apiKey or oauth2.

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | Yes |  |
| `mediaId` | query | string (uuid) | Yes | Id of the video to remove from this channel. |

### Responses

- `200`: The channel after the video was removed
- `400`: Bad Request
- `401`: Unauthorized — missing, invalid, or expired API key or OAuth access token
- `403`: Forbidden — credential does not have the required current Ours permission
- `404`: Not Found
- `500`: Internal Server Error

#### `200` response body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | Yes |  |
| `accountId` | string | Yes |  |
| `name` | string | Yes |  |
| `description` | string \| null | No |  |
| `brandColor` | string \| null | No |  |
| `logoMediaId` | string \| null | No |  |
| `footerText` | string \| null | No |  |
| `isPublished` | boolean \| null | No |  |
| `createdAt` | string \| null | No |  |
| `updatedAt` | string \| null | No |  |
| `resolvedValues` | object \| null | No |  |
| `resolvedValues.mediaCount` | integer | Yes |  |
| `resolvedValues.embedUrl` | string | Yes |  |
| `resolvedValues.embedCode` | string | Yes |  |

Full schema: [OpenAPI specification](https://docs.oursprivacy.com/openapi-platform.json).

## POST /rest/v1/video-channels/{id}/reorder

Set the display order of a channel’s videos. Send every video id currently in the channel in the order you want them shown — index 0 appears first. A partial list, or an id that is not in the channel, returns 400 so a caller working from a stale view learns it is out of date instead of getting a partial write. Requires API-key scope or current OAuth user permission: videoChannel:update

Request URL: `POST https://app.oursprivacy.com/rest/v1/video-channels/{id}/reorder`

Authentication: apiKey or oauth2.

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | Yes |  |

### Request body (`application/json`, required)

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `mediaIds` | (string (uuid))[] | Yes | Every video id currently in the channel, in the order you want them shown. Partial lists and ids that are not in the channel are rejected. |

### Responses

- `200`: The channel after reordering
- `400`: Bad request — `mediaIds` omitted a video in the channel or included an id that is not in it.
- `401`: Unauthorized — missing, invalid, or expired API key or OAuth access token
- `403`: Forbidden — credential does not have the required current Ours permission
- `404`: Not Found
- `500`: Internal Server Error

#### `200` response body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | Yes |  |
| `accountId` | string | Yes |  |
| `name` | string | Yes |  |
| `description` | string \| null | No |  |
| `brandColor` | string \| null | No |  |
| `logoMediaId` | string \| null | No |  |
| `footerText` | string \| null | No |  |
| `isPublished` | boolean \| null | No |  |
| `createdAt` | string \| null | No |  |
| `updatedAt` | string \| null | No |  |
| `resolvedValues` | object \| null | No |  |
| `resolvedValues.mediaCount` | integer | Yes |  |
| `resolvedValues.embedUrl` | string | Yes |  |
| `resolvedValues.embedCode` | string | Yes |  |

Full schema: [OpenAPI specification](https://docs.oursprivacy.com/openapi-platform.json).
