Once Content Ingest Overview

Product(s)
SSAI
Role(s)
API Developer
Task(s)
Add Videos/Assets
Topic(s)
Authentication
Notifications

This topic provides a guide to using the Brightcove Once Ingest API.

Overview

Brightcove’s Once API Ingest service is a RESTful API that accepts HTTPS POST requests, supplying JSON as the data structure and passing the API key in the header. When an API Ingest job is successfully submitted, core renditions required for delivery on the Once VOD platform are generated. Videos at your SourceURLs must be progressive formats and publicly addressable URLs. Ingesting files via S3 is also supported by the API Ingest system as a source location. If your files are publicly available, no further action is necessary. If your files require authentication, you will have to add `ONCE` and 'Zencoder' user to your Bucket policy.

Best practices

As a best practice recommendation your source video should be encoded with a video bitrate between 5-10 Mbps, frame size of 1920x1080 and contain keyframes at least every 6 seconds.

Base URL and Syntax

API Base URL:

https://api.unicornmedia.com/ingest-api/

Syntax:

https://api.unicornmedia.com/ingest-api/{domainId}/catalogs/{catalogId}

Example:

https://api.unicornmedia.com/ingest-api/b207b479-c841-4095-8918-978be9e18dee/catalogs/bc6cb7d4-be99-471b-adf3-7c501172b317

SNS-based ingest job

SNS Content Ingest is the service that allows for the automated ingest of assets and metadata from an Amazon SNS Topic to the Once platform. The SNS Ingest API waits for SNS Messages from all topics to which it is subscribed. Content is passed to the API by posting a Notification message to a topic that SNS Ingest API is subscribed to.

The following steps will be necessary to ensure Brightcove can configure the proper mechanisms to pull content from your AWS account.

  1. The SNS Topic ARN
  2. Allow the Brightcove AWS account root permission to subscribe to the SNS topic
    • Brightcove Root: arn:aws:iam::453163911362:root
    • Contact Brightcove to complete the configuration and submit a subscription request to your topic
  3. Allow permissions to the transcoding engine when using S3 buckets with your content storage

Example policy statement

{
    "Sid": "console_pub",
    "Effect": "Allow",
    "Principal": {
        "AWS": "arn:aws:iam::453163911362:root"
    },
    "Action": ["SNS:Subscribe",
    "SNS:Receive"],
    "Resource": "{Desired_Topic_ARN}",
    "Condition": {
        "StringEquals": {
            "SNS:Protocol": "sqs"
        }
    }
}

Using S3 buckets

If the bucket is not publicly accessible, the Brightcove transcoding engine will need to be granted access through a bucket policy or to the Brightcove AWS account.

Option #1 - Create a bucket policy

To set up a bucket policy, login to your AWS Console, select your bucket on the left side of the screen, then click "properties". On the last row click "Add bucket policy". We'll put a Bucket Policy together below, which you'll copy into the Bucket Policy text box.

Sample Bucket policy including permission for both Zencoder and Once AWS Principal:

{
  "Version": "2008-10-17",
  "Id": "ZencoderBucketPolicy",
  "Statement": [{
      "Sid": "Stmt1295042087538",
      "Effect": "Allow",
      "Principal": {
        "AWS": [
          "arn:aws:iam::395540211253:root",
          "arn:aws:iam::453163911362:root"
        ]
      },
      "Action": [
        "s3:GetObjectAcl",
        "s3:GetObject",
        "s3:PutObjectAcl",
        "s3:PutObject",
        "s3:ListMultipartUploadParts"
      ],
      "Resource": "arn:aws:s3:::BUCKET-NAME/*"
    },
    {
      "Sid": "Stmt1295042087538",
      "Effect": "Allow",
      "Principal": {
        "AWS": [
          "arn:aws:iam::395540211253:root",
          "arn:aws:iam::453163911362:root"
        ]
      },
      "Action": [
        "s3:ListBucketMultipartUploads",
        "s3:GetBucketLocation"
      ],
      "Resource": "arn:aws:s3:::BUCKET-NAME"
    }
  ]
}

Notes:

  • NOTE: For setting up a Bucket Policy for Once, customers would need to give access to these two AWS Principal for Brightcove to be able to complete Ingestion successfully:
    code>"arn:aws:iam::395540211253:root", // Zencoder's AWS Principal 
    
    "arn:aws:iam::453163911362:root" // Once AWS Principal

There is only one change you will have to make to this bucket policy before it's ready to go.

  1. Replace BUCKET-NAME with the name of your bucket. Leave the /* at the end of the line, as that will apply the policy to every file within the bucket.
  2. Optionally, replace the Action array with the actions you want to allow. Valid actions that Brightcove may need are:

    Object Permissions - first action array in the example above

    • s3:PutObject - allow Brightcove to upload files to the bucket
    • s3:GetObject - allow Brightcove to download files from the bucket
    • s3:GetObjectAcl - allow Brightcove to get ACL permissions for files
    • s3:PutObjectAcl - allow Brightcove to set ACL permissions for other users on files
    • s3:ListMultipartUploadParts - allow Brightcove to list which parts of a multipart file have been uploaded to the bucket

    Bucket Permissions - second action array in the example above

    • s3:GetBucketLocation - allow Brightcove to get the location of the bucket (US, EU, Asia, etc.)
    • s3:ListBucketMultipartUploads - allow Brightcove to view any multipart uploads currently happening on the bucket

    Example: If you want Zencoder to be able to download and upload files, replace the first Action array with:

    ["s3:PutObject", "s3:GetObject"]

Note: If the source files are stored on S3, the URLs should be in the format s3://BUCKET/KEY to ensure the URLs are signed appropriately.

If you'd like to build your own Bucket Policy, you can use Amazon's Policy Generator. Use arn:aws:iam::395540211253:root as the AWS Principal to allow Brightcove access.

Option #2 - grant access to Brightcove AWS

Grant Access to the Brightcove AWS account at aws@zencoder.com. If the setup requires the canonical ID you can use:

6c8583d84664a381db0c6af0e79b285ede571885fbe768e7ea50e5d3760597dd

Example ingest syntax

Request Header

Required HTTP Header:

X-BC-ONCE-API-KEY : {yourApiKey}

Schema

See Appendix A

Example Body

{
    "title": "Wildlife 07",
    "foreignKey": "wildlife07",
    "keywords": [
        "mammals",
        "tigers"
    ],
    "description": "some description",
    "metadata": {
        "hello": "world",
        "foo": "bar",
        "PassThruMetadata": "hello world",
        "JobID": "someJobId"
    },
    "media": {
        "sourceURL": "http://fileserver.com/videos/Wildlife.wmv"
    },
    "priority": "normal",
    "publicationRules": [
        {
            "channel": "a8cf98a9-8946-4bd4-b97c-a2b5dbc635c5",
            "startDate": 1412025402,
            "endDate": 1601414189,
            "clientFilters": [
                {
                    "variableName": "IpAddress",
                    "value": "127.0.0.1",
                    "filterType": "Equals",
                    "isDenied": true
                }
            ],
            "countryRules": [
                {
                    "countryCode": "UK",
                    "isDenied": true
                }
            ]
        }
    ],
    "cuePoints": [
        {
            "valueIn": 10,
            "unit": "Seconds"
        },
        {
            "valueIn": 25,
            "unit": "Seconds"
        }
    ],
    "timedText": [
    {
        "media" : {
          "sourceURL": "http://fileserver.com/filenameEN.xml"},
        "timedTextType": "SUBTITLE",
        "languages": ["en"]
    },
    {
        "media" : {
          "sourceURL": "http://fileserver.com/filenameFR.srt"},
        "timedTextType": "SUBTITLE",
        "languages": ["fr"]
    },
    {
        "media" : {
          "sourceURL": "http://fileserver.com/filenameEN.dfxp"},
        "timedTextType": "CAPTION",
        "languages": ["en"]
    },
    {
        "media" : {
          "sourceURL": "http://fileserver.com/filenamemulti.xml"},
        "timedTextType": "SUBTITLE",
        "languages": ["en", "fr"],
        "alternateId": "Bazinga"
    }
  ],
  "notifications" : [
    {
      "target" : "http://fileserver.com/notification-spy/record/JessePublish"
    },
    {
      "target" : "http://fileserver.com/notification-spy/record/JesseError",
      "notificationType" : "error"
    }
  ]
}

Response

Body (error)

{
    "requestId": "2796350e-2125-4f04-b33a-59488aaa76c7",
    "error": "Validation Errors",
    "fieldErrors": {
        "publicationRule": [
            "Publication rule with end date 0.0 is in the past.",
            "Publication rule end date: 0.0 preceeds 1412025402"
        ]
    }
}

Body (success)

{
    "requestId": "2796350e-2125-4f04-b33a-59488aaa76c7"
}

Brief Object Explanation

The table below can be used as a quick start for the major fields required for content ingestion along with a description. Please see the ingest schema for a full object mapping. If the required fields are not present in the API request; a response body will be returned with a corresponding validation error. Note: While we recommend the use of an optional field title for search and human readability, only the following highlighted fields are required for all ingest job requests.

Object Sub-Object Required Description
title   No Title of the asset, used for subsequent notifications and item lookup (emojis are not allowed)
foreignKey   Yes Unique identifier per domain to indicate a media item and its associations
keywords   No Keywords used to describe the media item
description   No Brief description of the media item (emojis are not allowed)
metadata   No Key-value pairs that can be stored with a media item and dynamically retrieved for audience beaconing or ad server requests
media   Yes Container for the defined source video
  sourceURL Yes Location of the video media item
timedText   No Defining or association closed captioning and/or subtitles to ingest in conjunction to the video media item
  media Yes Container for the defined source document of a subtitle or flagged as passthrough when the document is embedded on the video container
  timedTextType Yes Defines the timed text output as a subtitle, closed-caption, or embedded
  languages Yes Country code defined by ISO 639-1
  alternateId No Defines a timed text output when multiple variations of the same language is utilized. Output will be named as "{language}-{alternateId}"
priority   No Reserved for future use.
publicationRules   No Sets timing, geo filtering, and client filters to restrict content based on business requirements. By default, publication rules are open for 10 years from when account was opened. Please see Media Management for configuration details.
  channel Yes The channel Id associated with the domain; by default, a domain contains a single channel. If there are additional channels in a domain, this must be specified
  startDate Yes Begin content availability in epoch time (seconds)
  endDate Yes End content availability in epoch time (seconds)
  clientFilters No Allows the setting of client restrictions based on IP Address, useragent, or referring host
  countryRules No Geo restrictions based on ISO 639-1 country codes.
cuePoints   No Segmentation points of the mediaitem to insert midroll ads (when available and configured).
  valueIn Yes Value of the cuepoint in relation to the content duration; This value must be an integer
  unit Yes Unit of measurement for the valueIn; currently only "seconds" is supported

Ingest Schema

{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "type": "object",
    "title": "root",
    "description": "Ingest API Container",
    "additionalProperties": false,
    "properties": {
        "title": {
            "type": "string",
            "description": "The title of the asset",
            "minLength": 0,
            "maxLength": 255,
            "additionalProperties": false
        },
        "foreignKey": {
            "type": "string",
            "description": "The unique identifier for the asset",
            "minLength": 1,
            "maxLength": 255,
            "additionalProperties": false
        },
        "keywords": {
            "type": "array",
            "description": "An array of strings for the asset",
            "additionalProperties": false,
            "items": [
                {
                    "type": "string",
                    "description": "A keyword string value for the asset",
                    "minLength": 1,
                    "maxLength": 1000,
                    "additionalProperties": false
                }
            ],
            "required": [
                "0"
            ]
        },
        "description": {
            "type": "string",
            "description": "A description of the asset",
            "minLength": 0,
            "maxLength": 4000,
            "additionalProperties": false
        },
        "metadata": {
            "type": "object",
            "description": "An array of key value pairs for Extended Metadata",
            "additionalProperties": true,
            "properties": {
                "key": {
                    "type": "string",
                    "description": "The key of an Extended Metadata key value pair",
                    "minLength": 0,
                    "additionalProperties": false
                }
            }
        },
        "media": {
            "type": "object",
            "description": "Container for the source URL of the asset being ingested",
            "additionalProperties": false,
            "properties": {
                "sourceURL": {
                    "type": "string",
                    "description": "The URL string to the source asset",
                    "minLength": 1,
                    "maxLength": 1000,
                    "additionalProperties": false
                }
            },
            "required": [
                "sourceURL"
            ]
        },
        "priority": {
            "type": "string",
            "description": "Denotes the transcode priority of the asset",
            "minLength": 0,
            "additionalProperties": false,
            "enum": [
                "Normal"
            ]
        },
        "publicationRules": {
            "type": "array",
            "description": "An array of Publication Rules for the asset",
            "minItems": 1,
            "uniqueItems": false,
            "additionalProperties": false,
            "items": {
                "type": "object",
                "description": "Container for Client Filters and Country Rules for the Publication Rules",
                "additionalProperties": false,
                "properties": {
                    "channel": {
                        "type": "string",
                        "description": "The Channel Guid for the Publication Rule",
                        "minLength": 36,
                        "maxLength": 36,
                        "additionalProperties": false
                    },
                    "startDate": {
                        "type": "integer",
                        "description": "The start date for the Publication Rule",
                        "minimum": 0,
                        "maximum": 2147483647,
                        "additionalProperties": false
                    },
                    "endDate": {
                        "type": "integer",
                        "description": "The end date for the Publication Rule",
                        "minimum": 0,
                        "maximum": 2147483647,
                        "additionalProperties": false
                    },
                    "clientFilters": {
                        "type": "array",
                        "description": "And array of Client Filters for the Publication Rule",
                        "minItems": 1,
                        "uniqueItems": false,
                        "additionalProperties": false,
                        "items": {
                            "type": "object",
                            "description": "Container for a Client Filter",
                            "additionalProperties": false,
                            "properties": {
                                "variableName": {
                                    "type": "string",
                                    "description": "The variable name that the Client Filter will key off of",
                                    "additionalProperties": false,
                                    "enum": [
                                        "IpAddress",
                                        "UserAgent",
                                        "ReferringHost"
                                    ]
                                },
                                "value": {
                                    "type": "string",
                                    "description": "The value that the Client Filter will key off of",
                                    "minLength": 0,
                                    "maxLength": 255,
                                    "additionalProperties": false
                                },
                                "filterType": {
                                    "type": "string",
                                    "description": "The type of filtering used to compare the value",
                                    "additionalProperties": false,
                                    "enum": [
                                        "Equals",
                                        "NotEquals",
                                        "In",
                                        "NotIn",
                                        "Contains",
                                        "NotContains",
                                        "StartsWith",
                                        "NotStartsWith",
                                        "EndsWith",
                                        "NotEndsWith"
                                    ]
                                },
                                "isDenied": {
                                    "type": "boolean",
                                    "description": "Denotes whether a successful comparison of the Client Filter is denied or allowed",
                                    "additionalProperties": false
                                }
                            },
                            "required": [
                                "variableName",
                                "value",
                                "filterType",
                                "isDenied"
                            ]
                        },
                        "required": [
                            "0"
                        ]
                    },
                    "countryRules": {
                        "type": "array",
                        "description": "An array of Country Rules for the asset",
                        "minItems": 1,
                        "uniqueItems": false,
                        "additionalProperties": false,
                        "items": {
                            "type": "object",
                            "description": "Container for the Country Rule",
                            "additionalProperties": false,
                            "properties": {
                                "countryCode": {
                                    "type": "string",
                                    "description": "The Country Code for the Country Rule",
                                    "minLength": 2,
                                    "maxLength": 2,
                                    "additionalProperties": false,
                                    "enum": [
                                        "AF", "AL", "DZ", "AS", "AD", "AO", "AI", "AQ", "AG", "AR", "AM", "AW", "AU", "AT", "AZ", "BS", "BH", "BD", "BB", "BY", "BE", "BZ", "BJ", "BM", "BT", "BO", "BA", "BW", "BR", "IO", "VG", "BN", "BG", "BF", "MM", "BI", "KH", "CM", "CA", "CV", "CF", "TD", "CL", "CN", "CX", "CC", "CO", "KM", "CK", "CR", "HR", "CU", "CY", "CZ", "CD", "DK", "DJ", "DM", "DO", "EC", "EG", "SV", "GQ", "ER", "EE", "ET", "FK", "FO", "FJ", "FI", "FR", "PF", "GA", "GM", "GE", "DE", "GH", "GI", "GR", "GL", "GD", "GU", "GT", "GN", "GW", "GY", "HT", "VA", "HN", "HK", "HU", "IS", "IN", "ID", "IR", "IQ", "IE", "IM", "IL", "IT", "CI", "JM", "JP", "JE", "JO", "KZ", "KE", "KI", "KW", "KG", "LA", "LV", "LB", "LS", "LR", "LY", "LI", "LT", "LU", "MO", "MK", "MG", "MW", "MY", "MV", "ML", "MT", "MH", "MR", "MU", "YT", "MX", "FM", "MD", "MC", "MN", "ME", "MS", "MA", "MZ", "NA", "NR", "NP", "NL", "AN", "NC", "NZ", "NI", "NE", "NG", "NU", "KP", "MP", "NO", "OM", "PK", "PW", "PA", "PG", "PY", "PE", "PH", "PN", "PL", "PT", "PR", "QA", "CG", "RO", "RU", "RW", "BL", "SH", "KN", "LC", "MF", "PM", "VC", "WS", "SM", "ST", "SA", "SN", "RS", "SC", "SL", "SG", "SK", "SI", "SB", "SO", "ZA", "KR", "ES", "LK", "SD", "SR", "SJ", "SZ", "SE", "CH", "SY", "TW", "TJ", "TZ", "TH", "TL", "TG", "TK", "TO", "TT", "TN", "TR", "TM", "TC", "TV", "UG", "UA", "AE", "GB", "US", "UY", "VI", "UZ", "VU", "VE", "VN", "WF", "EH", "YE", "ZM", "ZW"
                                    ]
                                },
                                "isDenied": {
                                    "type": "boolean",
                                    "description": "Denotes whether a successful comparison of the Client Filter is denied or allowed",
                                    "additionalProperties": false
                                }
                            },
                            "required": [
                                "countryCode",
                                "isDenied"
                            ]
                        },
                        "required": [
                            "0"
                        ]
                    }
                },
                "required": [
                    "channel",
                    "startDate",
                    "endDate"
                ]
            },
            "required": [
                "0"
            ]
        },
        "cuePoints": {
            "type": "array",
            "description": "An array of Cue Points for the asset",
            "minItems": 1,
            "uniqueItems": true,
            "additionalProperties": false,
            "items": [
                {
                    "type": "object",
                    "description": "A key value pair of the time in which the Cue Point and unit type of the value",
                    "additionalProperties": false,
                    "properties": {
                        "valueIn": {
                            "type": "integer",
                            "description": "The time in which the Cue Point will be inserted",
                            "minimum": 0,
                            "maximum": 2147483647,
                            "additionalProperties": false
                        },
                        "unit": {
                            "type": "string",
                            "description": "The type of unit the time value",
                            "minLength": 0,
                            "additionalProperties": false,
                            "enum": [
                                "Seconds"
                            ]
                        }
                    },
                    "required": [
                        "valueIn",
                        "unit"
                    ]
                }
            ],
            "required": [
                "0"
            ]
        },
        "timedText": {
            "type": "array",
            "description": "An array of Timed Text items for the asset",
            "minItems": 1,
            "uniqueItems": true,
            "additionalProperties": false,
            "items": [
                {
                    "type": "object",
                    "description": "Container describing a timed text item and its contents",
                    "additionalProperties": false,
                    "properties": {
                        "media": {
                            "type": "object",
                            "description": "Container for the source URL of the timed text file being ingested",
                            "additionalProperties": false,
                            "properties": {
                                "sourceURL": {
                                  "type": "string",
                                   "description": "The URL string to the source asset",
                                    "minLength": 1,
                                    "maxLength": 1000,
                                  "additionalProperties": false
                               }
                           },
                         "required": [
                               "sourceURL"
                          ]
                        },
                        "timedTextType": {
                            "type": "string",
                            "description": "The type to categorize the timed text item",
                            "additionalProperties": false,
                            "enum": [
                                "Subtitle",
                                "Caption",
                                "Embedded"
                            ]
                        },
                        "languages": {
                          "type": "array",
                           "description": "An array of languages contained in the timed text asset",
                           "additionalProperties": false,
                           "items": [
                             {
                                "type": "string",
                                "description": "A ISO-639 language code to be found in the asset",
                                "minLength": 2,
                                "maxLength": 255,
                                "additionalProperties": false
                            }
                         ],
                          "required": [
                               "1"
                           ]
                       },
                       "alternateId": {
                            "type": "string",
                            "description": "The optional id to associate with the timed text item, used as a descriptor or to create uniqueness",
                            "minLength": 1,
                            "maxLength": 255,
                            "additionalProperties": false
                       }
                    },
                    "required": [
                        "media",
                        "timedTextType",
                        "languages"
                    ]
                }
            ],
            "required": [
                "0"
            ]
        },
        "notifications": {
            "type": "array",
            "description": "An array of Notifications to be fired during ingest",
            "minItems": 0,
            "uniqueItems": false,
            "additionalProperties": false,
            "items": [
                {
                    "type": "object",
                    "description": "A Notification Configuration",
                    "additionalProperties": false,
                    "properties": {
                        "target": {
                            "type": "string",
                            "description": "The HTTP endpoint or sns target for your notification",
                            "minimum": 0,
                            "additionalProperties": false
                        },
                        "notificationType": {
                            "type": "string",
                            "description": "The type of notification to be associated with, defaults to publish",
                            "minLength": 0,
                            "additionalProperties": false,
                            "enum": [
                                "publish", "transcode", "ingest", "update", "error", "any"
                            ]
                        },
                        "method": {
                            "type": "string",
                            "description": "The HTTP verb to use when sending an HTTP notification, defaults to POST",
                            "minLength": 0,
                            "additionalProperties": false,
                            "enum": [
                                "POST", "PUT", "GET"
                            ]
                        }
                    },
                    "required": [
                        "target"
                    ]
                }
            ],
            "required": [
                "0"
            ]
        }
    },
    "required": [
        "foreignKey",
        "media"
    ]
}