Media Sharing

In this topic, you will learn how to share videos from one Video Cloud account to another using the CMS API.

Introduction

Media sharing is a feature of Video Cloud that lets publishers share videos with other publishers, enabling you to more easily manage videos across multiple accounts. For example, publishers can keep a Master account of video content and then share videos out to other divisions or subsidiaries of the organization.

Note that all media sharing operation can be performed in Studio as well. See Managing Media Sharing Settings.

Shared media & billing

For information on how billing works for shared media, please see Media Sharing using the Media Module.

Terminology

In media sharing, there is a relationship between a Master account (that shares videos) and one or more Affiliate accounts (that receive shared videos) involved:

Media Sharing Terminology
Account Description
Master The account that created the original video.

The Master owns the content and is responsible for setting up, managing and providing content to Affiliates.

Affiliate The account that is receiving the video.

The Affiliate can accept content shared to it from a Master.

Relationship Describes the interaction between a Master and an Affiliate.

A relationship is comprised of a Master to share content, a Contract for accepting content, and an Affiliate to receive content.

Contract Describes sharing relationship between a Master and an Affiliate.

A contract is created by the Master, and then must be accepted for sharing to be enabled. The Affiliate can also specify whether shared videos are accepted automatically or must be approved one by one.

Base URL

As for all CMS API requests, the base URL for the operations discussed below is:

      https://cms.api.brightcove.com/v1

All endpoints discussed below will be appended to the base URL when you make requests.

Authentication

Authentication for requests requires an Authorization header:

          Authorization: Bearer {access_token}

The access_token is a temporary OAuth2 access token that must be obtained from the Brightcove OAuth service. For details on how to obtain client credentials and use them to retrieve access tokens, see the Brightcove OAuth Overview.

Note that all operations around relationships required new permissions:

      video-cloud/video/all
      video-cloud/sharing-relationships/read
      video-cloud/sharing-relationships/create
      video-cloud/sharing-relationships/update
      video-cloud/sharing-relationships/delete

Alternatively, you can just use:

      video-cloud/sharing-relationships/all

In the Studio API Authentication Admin page, two permissions are shown:

  • Sharing Read (equivalent to video-cloud/sharing-relationships/read)
  • Sharing Read/Write (equivalent to video-cloud/sharing-relationships/all)

Restrictions on sharing

By default, all videos can be shared. You can, however, prevent sharing if:

  • The affiliate account does not a have a custom field for which a value is set on the video in the master account
  • The master account has geo-filtering enabled, but the affiliate account does not

Custom field matching

You can enforce custom field matching for the master account, which means that video shares will fail if the video has values for custom fields that are not present in the affiliate account. Videos will still share successfully if the video does not have values for any non-matching custom fields

By default, custom field matching is not enforced.

If a video share fails because of non-matching custom fields, you will see an error like this in the response:

      {
        "video_id": "5691312273001",
        "affiliate_id": "47509719001",
        "affiliate_video_id": null,
        "status": "PROCESSING",
        "error_message": [{"error_code":"MISSING_CUSTOM_FIELDS","error_message":"Affiliate account is missing custom fields: [subject]"}],
        "shared_at": "2018-01-03T16:29:19.080Z",
        "updated_at": "2018-01-03T16:29:19.080Z"
      }

Geo-filtering matching

If geo-filtering matching is enabled for the master account, videos cannot be shared if the master account has geo-filtering enabled and the affiliate account does not.

By default, geo-filtering matching is not enforced. The enforce_geo setting is read-only in the CMS API, so you cannot turn it on or off with these operations.

The error will look like this:

      {
        "video_id": "5691312273001",
        "affiliate_id": "47509719001",
        "affiliate_video_id": null,
        "status": "PROCESSING",
        "error_message": [{"error_code":"INCOMPATIBLE_GEO","error_message":"Affiliate account is not configured for geo restriction."}],
        "shared_at": "2018-01-03T16:29:19.080Z",
        "updated_at": "2018-01-03T16:29:19.080Z"
      
      

See Update contract settings below to see how you update the contract settings to enforce custom field matching. Geo-filtering matching is a read-only setting and cannot be updated through the contract settings.

What is shared?

This section explains what gets shared, and how subsequent changes to the video are handled.

When the video is shared

Most of the video metadata fields are copied from the Master to the Affiliate account when the video is shared. The notable exceptions are:

  • id - the video will have its own unique id in the Affiliate account
  • date fields such as created_at and updated_at

All the video assets (renditions, images, text_tracks, etc.) are used by the Affiliate accounts for playback.

After the video is shared

After the video has been shared, some changes to the video in the Master account are automatically inherited by the Affiliate accounts, and some are not.

Video assets

Except for images, Master changes to the video assets are always inherited by Affiliates. Affiliates cannot change assets such as renditions, manifests, text tracks, or the digital master.

Changes to images by the Master are inherited by the Affiliate unless the Affiliate has replaced the image(s). Once an Affiliate changes an image, that image will no longer be inherited from the Master.

Video metadata

Any video metadata (such as the name, description, and reference id) can be modified by the Affiliate, and changes made on the Master video are not inherited by the Affiliate.

Resharing videos

Note, however, that if the Master re-shares the video (this can only be done through the CMS API, not in Studio), all assets and metadata (aside from data/time fields) will be shared to Affiliates, overwriting any changes the Affiliates have made.

Overview of media sharing steps

Setting up a relationship

Below is a summary of the operations for setting up a relationship (click on the operation name for more details):

Master operations

Get contract settings
Method/Endpoint

GET

/accounts/ master_account_id/contracts/settings

Description

Get the sharing contract settings of the account

Update contract settings
Method/Endpoint

PATCH

/accounts/ master_account_id/contracts/settings

Description

Update the sharing contract settings (custom field matching)

List affiliates
Method/Endpoint

GET

/accounts/ master_account_id/contracts/affiliates

Description

Get the affiliates of the account

Get affiliate
Method/Endpoint

GET

/accounts/ master_account_id/contracts/affiliates/ affiliate_account_id

Description

Get the contract with one affiliate

Add affiliate
Method/Endpoint

PUT

/accounts/ master_account_id/contracts/affiliates/ affiliate_account_id

Description

Create the sharing contract with an affiliate

Remove affiliate
Method/Endpoint

DELETE

/accounts/ master_account_id/contracts/affiliates/ affiliate_account_id

Description

Remove the sharing contract with an affiliate

Affiliate operations

List available contracts
Method/Endpoint

GET

/accounts/ affiliate_account_id/contracts

Description

Gets all contracts available to the account

Get contract for a specific account
Method/Endpoint

GET

/accounts/ affiliate_account_id/contracts/ master_account_id

Description

Gets a contract, if any, from a specific account

Approve a contract
Method/Endpoint

PATCH

PATCH /accounts/ affiliate_account_id/contracts/ master_account_id

Description

Accept and configure acceptance conditions of contract

Sharing videos

Video sharing operations are performed by the Master account. The Affiliate account can accept the share (if auto_accept is set to false) and can update shared video metadata and images using the standard Update Video operation.

Here are the sharing operations that can be performed once a relationship is set up (click on an operation name for more details):

List existing shares
Method/Endpoint

GET

/accounts/ master_account_id/videos/ video_id/shares

Description

Get a list of existing shares for a video - this is important because of the consequences of re-sharing a video when it has already be shared.

Share a video
Method/Endpoint

POST

/accounts/ master_account_id/videos/ video_id/shares

Description

Share a video to one or more affiliates - note that if the video has already been shared, this operation will re-share it - that is probably not what you want to do.

Share a video
Method/Endpoint

POST

/accounts/ master_account_id/videos/ video_id/shares

Description

Share a video to one or more affiliates - note that if the video has already been shared, this operation will re-share it - that is probably not what you want to do.

Un-share a video for an Affiliate
Method/Endpoint

DELETE

/accounts/ master_account_id/videos/ video_id/shares

Description

Un-shares a video for a specific Affiliates - note that un-sharing and re-sharing will result in the shared video having a new video id in the Affiliate account.

Affiliate operations

Accept a shared video
Method/Endpoint

PATCH

/accounts/ affiliate_account_id/videos/ video_id

Description

Accept a shared video (if auto_accept is turned off).

CMS API requests - setup

This section lists the CMS API operations involved in setting up media sharing.

Master operations

Get contract settings

Method

GET

Endpoint

/accounts/ master_account_id/contracts/settings

Request body

none

Sample response
{
  "enforce_custom_fields": false,
  "enforce_geo": true,
  "account_name": "Master Account"
}

The response has three fields. enforce_custom_fields is the only one that can be updated. enforce_geo is read-only. account_name is the name of the Master account, and it is read-only. It is empty if the name cannot be resolved.

Update contract settings

Method

PATCH

Endpoint

/accounts/ master_account_id/contracts/settings

Request body
{
  "enforce_custom_fields" : true
}
Sample response

204 NO CONTENT (empty response body)

Only enforce_custom_fields can be updated with this operation. If the request body includes enforce_geo, the request fails with a 400 error ({"enforce_geo":"ILLEGAL_FIELD"}) and nothing is saved. A Master account cannot read enforce_geo through the contract operations. Only the Affiliate account sees it, in contract_settings when it gets a single contract (see Get contract for a specific account).

List affiliates

Method

GET

Endpoint

/accounts/ master_account_id/contracts/affiliates

Request body

none

Sample response
[
  {
    "account_id": "20318290001",
    "approved": false,
    "account_name": "Brightcove Training"
  },
  {
    "account_id": "1485884786001",
    "approved": true,
    "account_name": "Brightcove Learning Doc Samples"
  },
  {
    "account_id": "1752604059001",
    "approved": true,
    "account_name": "BC Training Videos"
  }
]

Note: the value of the approved field indicates whether or not the Affiliate has approved the contract. The account_name field is empty if the name cannot be resolved.

Get affiliate

Method

GET

Endpoint

/accounts/ master_account_id/contracts/affiliates/ affiliate_account_id

Request body

none

Sample response
{
  "master_id": "57838016001",
  "affiliate_id": "1485884786001",
  "approved": true,
  "auto_accept": true,
  "approved_at": "2017-08-27T12:27:21.582Z",
  "created_at": "2017-08-23T17:45:41.556Z",
  "updated_at": "2017-08-27T12:27:21.582Z"
}

Add affiliate

Method

PUT

Endpoint

/accounts/ master_account_id/contracts/affiliates/ affiliate_account_id

Request body
{
  "affiliate_id":"affiliate_account_id"
}
Sample response
{
  "master_id": "57838016001",
  "affiliate_id": "1485884786001",
  "approved": false,
  "approved_at": null,
  "auto_accept": false,
  "created_at": "2017-08-23T17:45:41.556Z",
  "updated_at": "2017-08-23T17:45:41.556Z"
}

The affiliate_id in the request body must match the affiliate_account_id in the endpoint. No other field is accepted in the request body.

This operation does not approve the contract. The Affiliate must approve it (see Approve contract below). If the contract already exists, a repeated call returns the existing contract and keeps its approval state.

Both accounts must be enabled for media sharing. If not, the request fails with a 409 error and the error code SHARING_DISABLED. If the master account enforces geo-filtering and the affiliate account is not configured for geo restriction, the request fails with a 409 error and the error code INVALID_AFFILIATE.

If the CMS API cannot retrieve the data of the master account or of the affiliate account, the request fails with a 503 error and a Retry-After header. This also happens when the affiliate account id does not belong to any account. Check the account ids before you retry.

Remove affiliate

Method

DELETE

Endpoint

/accounts/ master_account_id/contracts/affiliates/ affiliate_account_id

Request body

none

Sample response

204 NO CONTENT (empty response body)

Affiliate operations

List available contracts

Method

GET

Endpoint

/accounts/ affiliate_account_id/contracts

Request body

none

Sample response
[
  {
    "master_id": "57838016001",
    "master_account_name": "BrightcoveLearning",
    "approved": false,
    "auto_accept": false,
    "enforce_custom_fields": false
  }
]

The two essential fields in the response are:

  • approved - when set to true, the contract is accepted by the Affiliate
  • auto-accept - when set to true, videos shared through this contract will be automatically accepted by the Affiliate; otherwise, they must be approved one by one

We will see how to update the contract below.

Get contract for a specific account

Method

GET

Endpoint

/accounts/ affiliate_account_id/contracts/ master_account_id

Request body

none

Sample response
{
  "master_id": "57838016001",
  "affiliate_id": "1485884786001",
  "approved": false,
  "auto_accept": false,
  "approved_at": null,
  "created_at": "2017-08-23T17:45:41.556Z",
  "updated_at": "2017-08-23T17:45:41.556Z",
  "contract_settings": {
    "enforce_custom_fields": false,
    "enforce_geo": false
  }
}

Approve contract

Method

PATCH

Endpoint

/accounts/ affiliate_account_id/contracts/ master_account_id

Request body
{
  "approved": true,
  "auto_accept": true
}
Sample response
{
  "master_id": "57838016001",
  "affiliate_id": "1485884786001",
  "approved": true,
  "auto_accept": true,
  "approved_at": "2017-08-27T12:27:21.582Z",
  "created_at": "2017-08-23T17:45:41.556Z",
  "updated_at": "2017-08-27T12:27:21.582Z"
}

If you include only "approved":true, each video will have to be approved individually.

CMS API requests - sharing

This section details the CMS API requests used in sharing videos. Media sharing operations are performed by the Master account. The Affiliate account can accept shares if auto_accept is turned off.

Master operations

List existing shares

To find out if a video has already been shared to other accounts, you can use the request below.

Method

GET

Endpoint

/accounts/ master_account_id/videos/ video_id/shares

Request body

none

Sample response
[
  {
    "video_id": "5553744346001",
    "affiliate_id": "1752604059001",
    "affiliate_video_id": "5553754248001",
    "status": "COMPLETE",
    "shared_at": "2017-08-27T14:35:01.890Z",
    "updated_at": "2017-08-27T14:35:25.630Z"
  },
  {
    "video_id": "5553744346001",
    "affiliate_id": "1485884786001",
    "affiliate_video_id": "5553758415001",
    "status": "COMPLETE",
    "shared_at": "2017-08-27T14:34:34.919Z",
    "updated_at": "2017-08-27T14:35:25.212Z"
  }
]

Sharing (or resharing) a video

The request described below will share a video to one or more Affiliate accounts.

Method

POST

Endpoint

/accounts/ master_account_id/videos/ video_id/shares

Request body
[
  { "id": "affiliate_account_id_1" },
  { "id": "affiliate_account_id_2" }
]
Sample response

Success response

[
{
  "video_id": "5553744346001",
  "affiliate_id": "1485884786001",
  "affiliate_video_id": null,
  "status": "PROCESSING",
  "shared_at": "2017-08-27T14:25:55.710Z",
  "updated_at": "2017-08-27T14:25:55.710Z"
}
]

Failure response

{
  "video_id": "5553744346001",
  "affiliate_id": "1485884786001",
  "affiliate_video_id": null,
  "status": "ERROR",
  "error_message": "[{\"error_code\":\"MISSING_CUSTOM_FIELDS\",\"error_message\":\"Affiliate account is missing custom fields: [myfieldname]\"}]",
  "shared_at": "2017-10-23T15:21:38.541Z",
  "updated_at": "2017-10-23T15:22:58.519Z"
}

Sharing will create a new video in the Affiliate's account. The state of the video share will be PROCESSING until the share is complete and the video is created in the Affiliate account. The Affiliate may still need to accept the video (if auto_accept is set to false on the contract by the Affiliate - see the previous section on setting up sharing).

Unsharing a video for an Affiliate

Method

DELETE

Endpoint

/accounts/ master_account_id/videos/ video_id/shares/ affiliate_account_id

Request body

none

Sample response

202 ACCEPTED (empty response body) - the response indicates that the request has been accepted for processing, but the operation may not be completed for a couple of minutes

Affiliate operations

Accept shared video

To accept a shared video, the Affiliate updates the shared video, setting its state to ACTIVE. (Setting the state to INACTIVE rejects the share.)

Method

PATCH

Endpoint

/accounts/ affiliate_account_id/videos/ affiliate_video_id

Request body

  {
    "state": "ACTIVE"
  }
Sample response
{
  "id": "5557656136001",
  "account_id": "1485884786001",
  "ad_keys": null,
  "clip_source_video_id": null,
  "complete": true,
  "created_at": "2017-08-30T13:35:51.796Z",
  "cue_points": [
  ],
  "custom_fields": {
  },
  "delivery_type": "dynamic_origin",
  "description": null,
  "digital_master_id": "4728546275001",
  "duration": 11111,
  "economics": "AD_SUPPORTED",
  "folder_id": null,
  "geo": null,
  "has_digital_master": true,
  "images": {
    "thumbnail": {
      "asset_id": "5473683978001",
      "remote": false,
      "src": "https://brightcove.vo.llnwd.net/e1/pd/57838016001/57838016001_5473683978001_4728519374001-th.jpg?pubId=1485884786001&videoId=5557656136001",
      "sources": [
        {
          "src": "https://brightcove.vo.llnwd.net/e1/pd/57838016001/57838016001_5473683978001_4728519374001-th.jpg?pubId=1485884786001&videoId=5557656136001",
          "height": 90,
          "width": 160
        },
        {
          "src": "https://brightcove.hs.llnwd.net/e1/pd/57838016001/57838016001_5473683978001_4728519374001-th.jpg?pubId=1485884786001&videoId=5557656136001",
          "height": 90,
          "width": 160
        }
      ]
    },
    "poster": {
      "asset_id": "5473684427001",
      "remote": false,
      "src": "https://brightcove.vo.llnwd.net/e1/pd/57838016001/57838016001_5473684427001_4728519374001-vs.jpg?pubId=1485884786001&videoId=5557656136001",
      "sources": [
        {
          "src": "https://brightcove.vo.llnwd.net/e1/pd/57838016001/57838016001_5473684427001_4728519374001-vs.jpg?pubId=1485884786001&videoId=5557656136001",
          "height": 720,
          "width": 1280
        },
        {
          "src": "https://brightcove.hs.llnwd.net/e1/pd/57838016001/57838016001_5473684427001_4728519374001-vs.jpg?pubId=1485884786001&videoId=5557656136001",
          "height": 720,
          "width": 1280
        }
      ]
    }
  },
  "link": null,
  "long_description": null,
  "name": "oystercatcher.mp4",
  "original_filename": "57838016001_4728546275001_4728519374001.mp4",
  "projection": null,
  "published_at": "2017-08-30T13:41:13.974Z",
  "reference_id": "2016-01-29T21:41:33.225Z-screencast-1280",
  "schedule": null,
  "sharing": {
    "by_external_acct": true,
    "by_id": "57838016001",
    "source_id": "4728519374001",
    "to_external_acct": false,
    "by_reference": true
  },
  "state": "ACTIVE",
  "tags": [
    "newtag",
    "foo"
  ],
  "text_tracks": [
  ],
  "updated_at": "2017-08-30T13:41:14.075Z"
}

Set the state to INACTIVE to reject the share.

Note that there is no special notification indicating that a video has been shared to your account. However, if you search videos for state:pending, that will find any unaccepted shares. Alternatively, you can use the Shares Pending list in the Studio Media module to see and accept/reject pending shares:

Pending Shares
Pending Shares

Errors

Media sharing errors are not returned as a separate error response to the API request, but rather in an error_message field in the normal response:

      [
        {
          "video_id" : "1239817239128",
          "affiliate_id" : "32871239",
          "affiliate_video_id" : "30308254055202",
          "status" : "COMPLETE",
          "shared_at" : "2017-12-11T17:57:45.530Z",
          "updated_at" : "2017-12-11T18:03:32.789Z",
          "error_message" : "[{"error_code":"MISSING_CUSTOM_FIELDS","error_message":"Affiliate account is missing custom fields: [whisky]"}]"
        }
      ]

See the CMS API Error Reference for more details.

Limitations

Currently, media sharing has the following limitations:

  • DRM: media sharing via the CMS API is currently not supported for DRM-enabled accounts. Sharing videos from an account that is not DRM-enabled to an account that is DRM-enabled is supported, but the shared videos will not be packaged for DRM.
  • If the master account has set enforce_custom_fields in its contract settings to true, and then shares a video that has a custom field with a value that is not allowed by the affiliate account, that share attempt will fail. The share status will be updated with an error message something like this:

          [{"error_code": "ILLEGAL_CUSTOM_FIELD_VALUE", "error_message": "Illegal value for custom fields: [topic]"}]
          

    If the master account has set enforce_custom_fields in its contract settings to false, and then shares a video that has a custom field with a value that is not allowed by the affiliate account, then the share attempt will work, but the field with the bad value will not be included on the affiliate copy of the video.

  • When playing a shared video with SSAI, SSAI Macro replacement will use the metadata from the parent video instead of the child Video. SSAI will also skip the ad lookup if the parent video is marked as Advertising='Free', even if the child video is labeled as Ad Supported.