Skip to content Skip to main navigation Skip to footer

API In Nucleus

The API is not enabled on all instance by default. To request access to the API please submit a support ticket with Nucleus API in the title and our support team will action this.

1. Introduction

This guide outlines the operation of the Nucleus API which allows external systems to programmatically access details of awards, categories, entries and videos. All of the data that is used to build the structure of the viewing interface can be accessed via the API and used within another system.

The first part of this guide will detail the framework and how developers can access the data. The second part of the guide will explain to admin users how to create keys and give developers access to the information that they require.

2. Authentication Framework

In order to prevent unauthorised access to the data all API requests must be digitally signed. The approach employed is designed in accordance with the principles set out here: http://broadcast.oreilly.com/2009/12/principles-for-standardized-rest-authentication.html

This is implemented by adding the following 3 fields to each request as additional CGI parameters:

  • expires
    The time at which this request becomes invalid expressed as a unix timestamp i.e. seconds since 1/1/1970 (see Unix time ). This should generally be kept as low as possible – e.g. less than 60 seconds in the future. 
  • keyId
    The public key to authenticate against
  • signature
    A hash-based message authentication (HMAC) code (see https://en.wikipedia.org/wiki/Hash-based_message_authentication_code ) as generated by the hash_hmac PHP function (see http://php.net/manual/en/function.hash-hmac.php). The data used to generate the HMAC will be the endpoint path combined with the entirety of the query string (see https://en.wikipedia.org/wiki/Query_string) including the expiry and apiKey fields but excluding the hmac field itself. If data is passed using a POST instead of a GET then the HMAC should be based on what the query string would have looked like if the same data had been passed on the query string (in the same order that they occur in the POST). The HMAC should be generated from the data after it has been URL-encoded. The key used to generate the HMAC will be the private key which corresponds to the public key which has been used.

API keys are managed through the Nucleus administrative interface. The API Key administration page can be accessed through the “Misc → API Keys” page. This page lists current API keys and the corresponding private keys and allows new keys to be issued and existing keys to be revoked.

2.1. Signature Example 

If the entries.php endpoint is to be call with the following parameters:

  • awardId = 12
  • categoryId = 34

First the the expiry time and API key should add to these fields so that the query string is compiled from the following fields:

  • awardId = 12
  • categoryId = 34
  • expires = 1462802582 (replace this with a suitable future timestamp)
  • keyId = 5a3b403d4dcfb84f73f383d2e2b8f352 (replace this with your key ID)

This can then be converted to a query string thus:

awardId=12&categoryId=34&expires=1462802582&keyId=5a3b403d4dcfb84f73f383d2e2b8f352

The endpoint is added to the front thus:

entries.php?awardId=12&categoryId=34&expires=1462802582&keyId=5a3b403d4dcfb84f73f383d2e2b8f352

This is then used to generate the hmac. If the secret is, for example, 8iKDKfYOGfmBuLP+nR/nbU59Sh2rw9KV then the following PHP code can be used:

hash_hmac('sha256','entries.php?awardId=12&categoryId=34&expires=1462802582&keyId=5a3b403d4dcfb84f73f383d2e2b8f352','8iKDKfYOGfmBuLP+nR/nbU59Sh2rw9KV');

This gives the HMAC:

13d41665334bb60ee8bf7bdee22fe571291cbd3e4eb1f60f05aa31fc576ca2a6

Note – that although the request is sent to /api/entries.php, the hash is computed using the endpoint address without the initial “/api/”.

This is then appended to the query string to give the final complete URL

https://my.nucleus.domain.com/api/entries.php?awardId=12&categoryId=34&expires=1462802582&keyId=5a3b403d4dcfb84f73f383d2e2b8f352&signature=13d41665334bb60ee8bf7bdee22fe571291cbd3e4eb1f60f05aa31fc576ca2a6

This could equally well be a POST to https://my.nucleus.domain.com/api/entries.php with the following parameters:

  • awardId = 12
  • categoryId = 34
  • expires = 1462802582
  • keyId = 5a3b403d4dcfb84f73f383d2e2b8f352
  • signature = 13d41665334bb60ee8bf7bdee22fe571291cbd3e4eb1f60f05aa31fc576ca2a6

When using a post it is important that the parameters are passed in the same order as they were included in the query string when generating the signature.

3. Test Harness, Client Library and Sample Code

A simple test harness is available in the entry site administrative interface. This page can be accessed through the “Misc → API Test Harness” page. The test harness page also contains links to a PHP Client library to simplify access to the API and some sample code which uses this client library.

  1. Log into the Admin Interface
  2. Go to Actions>Misc
  3. Select API Test Harness in the System Administration Section
  4. The following page will contain examples and test parameters which can be set.

Note – you will need a Nucleus Admin user to access this page. Contact the Nucleus Admins and ask them to create a user for you.

3.1. Sample Code: API Wrapper Class

<?
 
class BAESClient {
	private $keyId;
	private $secret;
	private $baseUrl;
 
	function __construct($baseUrl,$keyId,$secret) {
		$this->baseUrl = $baseUrl;
		$this->keyId = $keyId;
		$this->secret = $secret;
	}
 
	function call($endpoint, $params) {
		ksort($params);
		$url = $this->baseUrl.'/'.$endpoint.'.php';
 
		$params['expires'] = time()+60;
		$params['keyId'] = $this->keyId;
		$sigStr = $endpoint.'.php?'.http_build_query($params);
 
		$params['signature'] = hash_hmac('sha256',$sigStr,$this->secret);
		// for debug
		// echo "$sigStr , $this->secret\n\n";
		// print_r($params);
		
		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL,$url);
		curl_setopt($ch, CURLOPT_POST, 1);
		curl_setopt($ch, CURLOPT_POSTFIELDS,$params);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		// for debug
		// curl_setopt($ch, CURLOPT_HEADER, true);
 
		$response = curl_exec ($ch);
		$responseCode = curl_getinfo($ch,CURLINFO_RESPONSE_CODE);
		curl_close ($ch);
 
		if ($responseCode !== 200) {
			if (preg_match('/<title>(.*?)<\/title>/is',$response,$matches)) $errors = array( $matches[1] );
			else $errors = array( $response );
			return array( $responseCode, array(), $errors );
		}
 
		$data = json_decode($response, true);
		if ($data===null) {
			$reponseCode = 500;
			$errors = array("Unexpected content in API response: ".substr($response,0,200));
			return array( $responseCode, array(), $errors );
		}
 
		if (!isset($data['status']) || !(isset($data['errors']) || isset($data['results']))) {
			$reponseCode = 500;
			$errors = array();
			if (!isset($data['status'])) $errors[] = "API response did not include a status field";
			else $errors[] = "API response did not include errors or results";
			return array( $responseCode, array(), $errors );
		}
 
		if (!isset($data['errors'])) $data['errors']=array();
		if (!isset($data['results'])) $data['results']=array();
 
		return array( $data['status'], $data['results'], $data['errors'] );
	}
 
}

3.2. Sample Code Using Wrapper Class

<?

include('../../lib/api/BAESClient.php');
 
/* here is an example with some parameters set - you will need to edit the videoId for this to work
$endpoint = 'video';
$params = array(
    'videoId' => '329',
    'type'  => 'watch',
    'userId'    => 'test_watch'
);
*/
$endpoint = 'awards';
$params = array();
 
// You will need to place your API Key ID and Secret key in here...
define('API_KEYID','################################');
define('API_SECRET','################################');
 
// You will need to place the base URL for your BAES installation in here...
define('API_BASE_URL','https://#####.#####.##/api/');
 
$baesClient = new BAESClient( API_BASE_URL, API_KEYID,API_SECRET);
 
header('Content-type: text/plain');
 
list($status, $results, $errors) = $baesClient->call($endpoint,$params);
 
echo "STATUS=$status\n";
print_r($results);
print_r($errors);

4. Test Harness, Client Library and Sample Code Javascript

A simple test harness is available in the entry site administrative interface. This page can be accessed:

  1. Log into the Admin Interface
  2. Go to Actions>Misc
  3. Select API Test Harness in the System Administration Section
  4. The following page will contain examples and test parameters which can be set.

The test harness page also contains client side and server side sample code.

A Javascript API Client library is available here: https://<Base URL for your BAES installation>/javascript/nucleusApiClient.mjs

Note: The Javascript client is designed for use in both server side and client side (in browser) applications.

***PLEASE NOTE*** that when using the API client in a browser you MUST NOT include the API key and secret. Instead you must implement a small server-side endpoint to implement the request signing. An example of what the server side signing endpoint is included below.

4.1. Client Side Example

Add this code to the web page

<script type="module">

// If this module fails to load you may need to host the nucleusApiClient.mjs file on the same domain as the page the code is running in
import NucleusClient from 'https://<Base URL for your BAES installation>/javascript/nucleusApiClient.mjs'

// Replace "https://app.your-company.com/api/nucluesRequestSigningURL.php" with the appropriate URL on the next line
var client = new NucleusClient('https://<Base URL for your BAES installation>/api/','https://app.your-company.com/api/nucluesRequestSigningURL.php');

// In this example we are going to get the details for the award with ID 280. Your award ID will be different
var endpoint = 'awards';
var awardId = 280;
var response = client.call(endpoint,{
    'awardId' : awardId,
    'expires' : Math.round((new Date()).getTime()/1000)+60
}).then(function(result) {
    // Do something with the result here
    console.log(result);
});
</script>

Add code something like this on your external application server at https://app.your-company.com/api/nucleusRequestSigningURL.php

<?
/*
----------------------------
Add in user authentication here in using whatever mechanism your system uses
----------------------------
*/

if(isset($_POST['endpoint']) && !empty($_POST['endpoint'])) {
    $keyId = '< PUT YOUR API KEY ID HERE >';
    $secret = '< PUT YOUR API SECRET HERE >';
    $params = $_POST;
    $endpoint = $params['endpoint'];
    unset($params['endpoint']);
    $params['keyId'] = $keyId;
    $sigStr = $endpoint.'.php?'.http_build_query($params);
    $signature = hash_hmac('sha256',$sigStr,$secret);
} else {
    $signature = '';
}
echo json_encode(array(
    'signature' => $signature,
    'keyId' => $keyId
));
exit;
?>

4.2. Server Side Example

In order to run this code you will first need to:

  1. Download the javascript client library from https://<Base URL for your BAES installation>/javascript/nucleusApiClient.mjs
  2. npm install node-fetch
import NucleusClient from './nucleusApiClient.mjs';

var client = new NucleusClient('https://<Base URL for your BAES installation>/api/','< PUT YOUR API KEY ID HERE >','< PUT YOUR API SECRET HERE >')

// In this example we are going to get the details for the award with ID 280. Your award ID will be different
var endpoint = 'awards';
var awardId = 280;
var response = client.call(endpoint,{
    'awardId' : awardId,
    'expires' : Math.round((new Date()).getTime()/1000)+60
}).then(function(result) {
    // Do something with the result here
    console.log(result);
});

5. Endpoints

The endpoints are listed below. Endpoints may accept additional query parameters as detailed below. Some of these parameters are mandatory – this is indicated below where this applies. All endpoints will return data as a JSON encoded data structure (see http://json.org/ ).

The data structure returned will be an associative array with three keys:

  • status: A numeric status code using the same codes as conventional http transfers i.e. 200 = OK, 403 = Forbidden etc
  • errors: An array of human-readable error messages
  • results: An array of associative arrays. If there are no results this will be an empty array (but this will not be treated as an error).

5.1. /api/awards.php

There are no additional input parameters options for this endpoint.

This endpoint will return an array of active awards with the following parameters for each item

  • awardId
    The award ID
  • name
    The name of the award
  • orderNumber
    An integer to indicate what order awards should be displayed in
  • opensAt
    The date and time when the award is open for entries expressed as a unix timestamp
  • lastCreateDate
    The date and time when award closes for new entries expressed as a unix timestamp
  • lastSubmitDate
    The date and time when award closes for submission of existing (already created) entries expressed as a unix timestamp

Example

Request

{ }

Response

[
    {
        "awardId": "123",
        "name": "Jedi Award 2023",
        "orderNumber": "1",
        "opensAt": "1680126900",
        "lastCreateDate": "1698792900",
        "lastSubmitDate": "1698792900"
    },
    {
        "awardId": "124",
        "name": "Jedi Award 2024",
        "orderNumber": "1",
        "opensAt": "1711752900",
        "lastCreateDate": "1722376500",
        "lastSubmitDate": "1722376500"
    },
    {
        "awardId": "127",
        "name": "Short Jedi Award 2024",
        "orderNumber": "2",
        "opensAt": "1665438900",
        "lastCreateDate": "1728597300",
        "lastSubmitDate": "1728510900"
    }
]

5.2. /api/categories.php

Additional parameters for this endpoint are:

  • awardId (mandatory)
    The award for which categories should be returned

This endpoint will return an array of categories for the specified award which will include the following parameters for each category:

  • categoryId
    The ID for the category
  • name
    The name of the category
  • type
    This is either “Performance” or “Production”
  • introMessage
    The viewing portal introductory message as defined in the category setup on BAFTA Nucleus
  • showOnViewingPortal
    Either 0 (do not show) or 1 (show) as set in the category setup in BAFTA Nucleus
  • votingSiteCategoryId
    The “Voting site category ID” as specified for the category in the category setup in BAFTA Nucleus

Example

Request

{
    "awardId": "123"
}

Response

[
    {
        "categoryId": "123",
        "name": "Best Hair",
        "introMessage": "",
        "showOnViewingPortal": "1",
        "votingSiteCategoryId": "0"
    },
    {
        "categoryId": "124",
        "name": "Best Mind Bending Skills",
        "introMessage": "",
        "showOnViewingPortal": "1",
        "votingSiteCategoryId": "0"
    },
    {
        "categoryId": "125",
        "name": "Most cool",
        "introMessage": "",
        "showOnViewingPortal": "1",
        "votingSiteCategoryId": "0"
    }
]

5.3. /api/entries.php

Additional parameters for this endpoint

  • awardId (mandatory)
    The award for which entry data should be returned.
  • status (
    If passed in then only entries with this status will be returned. Valid values are “unsubmitted”,”submitted” or “approved”.
  • categoryId
    The categoryId for which entries should be returned. If specified, only entries which are in this category will be returned.
  • entryId
    If this is specified then an array containing data about only this single entry will be returned. If this is combined with any other filters and the other filters do not match this entry ID then an empty set will be returned.
  • titleEquals
    If this is specified then only entries whose title matches the value provided will be returned. This filter is case insensitive. This can be combined with categoryId and status if you want to find only entries with the specified title, in the specified category and with the specified status.
  • titleContains
    If this is specified then only entries whose title contains the string provided will be returned. This filter is case insensitive. This can be combined with categoryId and status if you want to find only entries containing this text in the specified category and with the specified status.

This endpoint will return an array of approved entries with the following parameters for each entry:

  • entryId
    The entry ID
  • entryTitle
    The title of the entry – this will be taken from the question on the entry form for which the “Include on Entry list for entrant” field has been set to “1”.

N.B If no questions has been defined with “Include on Entry list for entrant” set to “1” then no entries will be returned by the API.

  • data
    The data from the entry form which has been given a “Title for viewing portal“. This data will be an associative array keyed on the field name as specified for the corresponding question definition in the “Title for viewing portal” field. Where the data field is a “Media Item” then the value for the question will be the string ‘mediaItem:’ followed by the media item type, followed by a numeric ID for the media item which can be passed to the mediaItem endpoint below e.g. “mediaItem:video:6
    Media Item Types are as follows:
    • Image
    • Video
    • Audio
    • Document
  • categoryNames
    An array of category names
  • categoryIds
    An array of category ID’s

Example

Request

{
    "awardId": "19",
    "titleContains": "day",
    "status": "submitted"
}

Response

[
    {
        "entryId": "12345",
        "status": "submitted",
        "categoryNames": [
            "Best Hair",
            "Most Cool",
        ],
        "categoryIds": [
            ”124”,”125”
        ],
        "entryTitle": "bedtime Jedi",
        "data": {
            "Main production country": "Zag",
            "Length": "4800",
            "Language": [
                "Zagdorp"
            ],
            "Year of Production": "2023",
            "Director 1": "James Jameson",
            "Cast 1": "Bob Ambleforth",
            "Cast 2": "",
            "Synopsis": "Jedi gets tired\r\nJedi goes to bed\r\nTHE END",
            "Visual Effects 1": "Fizz bang",
            "Visual": "mediaItem:image:999",
            "Screenwriter 1": "Simon Jones",
            "Co-producer 1": "Jim Joshing",
            "Film website": "",
            "Further images 1": "mediaItem:image:672",
            "Main still \/ preview image": "mediaItem:image:349",
            "Film excerpt 1": "mediaItem::0",
            "Film file": "mediaItem:video:263"
        }
    },
    {
         "entryId": "12345",
        "status": "submitted",
        "categoryNames": [
            "Best Mind Bending Skills",
            "Best Hair"
        ],
        "categoryIds": [
            "123",”124”
        ],
        "entryTitle": "Holiday Time Jedi",
        "data": {
            "Main production country": "Zog",
            "Length": "4800",
            "Language": [
                "Zorgon"
            ],
            "Year of Production": "2023",
            "Director 1": "James Anderson",
            "Cast 1": "Bob Wimblehurst",
            "Cast 2": "",
            "Synopsis": "Jedi goes on holiday\r\nGreat hilarity ensues\r\n",
            "Visual Effects 1": "Bag Whallop",
            "Visual": "mediaItem:image:5005",
            "Screenwriter 1": "Simon Beetles",
            "Co-producer 1": "Jim Anderson",
            "Film website": "",
            "Further images 1": "mediaItem:image:7350",
            "Main still \/ preview image": "mediaItem:image:7349",
            "Film excerpt 1": "mediaItem::273",
            "Film file": "mediaItem:video:2687"
        }
    }
]

5.4. /api/mediaItem.php

Note – Only MediaItems associated with submitted entries can be retrieved

Additional parameters for this endpoint

  • mediaItemId (mandatory)
    The ID of the mediaItem being requested.
    This can be a single ID, or a comma separated list of up to 100 media item IDs.
    If multiple ID’s are provided they MUST all be of the same type i.e. all video, or all images.
    If multiple media items are required please try to request these in one go rather than making many separate individual requests.
  • type (mandatory)
    When the media type is “video” then this determines whether a link to the HLS stream, a transcoded MP4 file, or the originally uploaded file should be returned as follows:
    • stream (JSON data including both HLS m3u8 file and mp4 alternative will be returned. This JSON can be fed straight to a BitMovin player)
    • download (the URL for a transcoded MP4 file will be returned)
    • original (the URL for the original untranscoded file will be returned)
    • preview (the URL for a thumbnail image for the video)
  • When the media type is “image” this determines whether the original file is downloaded or a resized preview version is supplied. Options for images are:
    • preview
    • original
  • When the media type is “document” then only valid type is:
    • download

If you supply multiple You can only request one type of media in one call.

  • viewerId (mandatory)
    All watch or download requests are logged by BAFTA Nucleus. This must be the numeric ID for a viewer as defined in Nucleus. The viewer must have permission to view the requested mediaItem(s). If the viewer specified doesn’t have permission to view any of the requested mediaItems then these mediaItems will simply be completely omitted from the data returned.
  • validityHours
    The duration for which the link which is returned should remain functional (in hours). After this time the video will no longer be playable. The validity time for the URL starts from when the URL is generated by the API. If no value is specified then the default value used by the entry site will be substituted
  • maxUses
    The number of times that the link can be used to access the content. If this parameter is missing it defaults to 3. If unlimited access is required this should be set to some arbitrarily high number e.g. 9999

This endpoint will return an associative array of URL’s keyed on the mediaItemId.

An example of the data returned when requesting multiple mediaItems is included below. 

N.B. This example is just for illustration and couldn’t actually be generated on the live system because the data in this example includes mediaItems of differing types – on the live system you can only request items of one type at a time. If you include ID’s for items that don’t support this type then the erroneous ID’s will still be included in the output data, but with an “Invalid Type” error. So, if the requested type is “original” then you can request multiple mediaItems of any variety in the same request (since videos, images and documents all support the “original” type). If the requested type is “preview” then you can request images and videos, but documents will return an “Invalid type” error because documents don’t support the preview type

{
    // Video stream
    289: {
            url: https://…<link to get json stream data>…
    },
 
    // Video mediaItem requested with type=download
    289: {
            url: https://…<link to download mp4>…
    },
 
    // Video mediaItem requested with type=original
    289: {
            url: https://…<link to download original video file>…
    },
 
    // Video mediaItem requested with type=preview
    289: {
            url: https://…<link to download thumbnail image>…
    },
 
    // Image mediaItem requested with type=preview
    289: {
            url: https://…<link to download thumbnail image>…
    },
 
    // Image mediaItem requested with type=download
    289: {
            url: https://…<link to download original image file>…
    },
 
    // mediaItem requested which is incompatible with the requested type
    // e.g. when a “preview” of a document is requested
    288: {
     error: “Invalid Type”
    }
}

The link to get json stream data in the example above will return JSON data in this format.

{
	"result": {
		"hls": "https:\/\/d3cszrd24af8ic.baftaelectron.com\/hls\/…\/index.m3u8",
		"mp4": [{
			"url": "https:\/\/d3cszrd24af8ic.cloudfront.net\/….",
			"type": "video\/mp4",
			"height": "480",
			"label": "480p"
		}, {
			"url": "https:\/\/d3cszrd24af8ic.cloudfront.net\/…",
			"type": "video\/mp4",
			"height": "720",
			"label": "720p"
		}]
	}
}

API Information for Nucleus Admins

The above instructions should be given to your developers but there is some setup required by Nucleus Admins which is covered in the above guide. For convenience this has been broken down here as non-developers might find the above instructions confusing.

The API is accessed using existing functionality, including an admin account, Viewing Portal Title, Award and Category ID’s. Largely an award using the API should be set up in the normal way but it is likely developers will ask you for key information items and this guide will enable you to prepare this form them in advance.

Note – Only Entry Data and MediaItems associated with Approved entries can be retrieved.

Items to Prepare in Advance

  • Generate an Admin Account -The API will access the data using an admin account and the developer will need this in order to generate a test harness. When you create the account make sure it only has access the projects the API needs to access. The API can only export form Awards where it has permissions. For more information on creating accounts read the Admin User guide.
  • Provide the Award ID/s – Each Award has an ID and the developer will need this to access the data. In the Admin Interface, go to Actions>Awards. On the table take the number from the ID column for all awards you want the developer to access.
  • Provide the Category ID/s – Each Category has an ID and the developer will need this to access the data. In the Admin Interface, go to Actions>Categories. On the table take the number from the ID column for all categories you want the developer to access.
  • Define a Question for Include on Entry List for Entrants – This is normally completed as part of the award set-up but has been included here as a reference. In order for the API to work one question needs to be set to appear on the Entrant Dashboard. To action this in the Admin Interface for to Actions>Questions. Look in the Display on Entrant column for a 1. If you can’t find this, choose a question, title is the best, and click Edit. On the next screen under Options select Position 1 for Include on Entry list for entrant.
  • Set a Title for API name – for each item of data that you wish the API to access it must have a valid name set in the API name field. To set this in the Admin Interface for to Actions>Questions. Choose a question where you wish to include the data set and click Edit. On the next screen under Options enter a value in API name. This data set will not be accessible for the API.

How to Generate an API Key

The developer will not be able to access the data without a valid API key. The developers, once they have an account, may generate this themselves but as the process is simple it can speed up the process if you generate this in advance and send to your developer.

  1. Log into the Admin Interface
  2. Go to Actions>Misc
  3. Under System Administration select API Keys
  4. On the next page click Add
  5. An API Key and Secret will be generated
  6. Copy these and keep them secure as the developer will need both
  7. Enter a name in Notes so you can retrieve the key and secret in future
  8. Click Save and Close

How to Set a Question in the API to be Displayed in the Viewing Interface

There are cases where a question needs to be used in the API to be displayed in the Viewing Interface. This is something you can set from the Question Settings.

  1. Log into the Admin Interface
  2. Go to Actions>Question list
  3. Click Edit on the question you want to display in the Viewing Portal
  4. Scroll down to the Options section
  5. Fill in the API name field. Please note that this must be unique as it won’t work if there are duplicates names in the same award
  6. Click Save & Close
  7. Your question will now appear in the API

Note – Once you set this up, always check the Viewer’s permission have been set up accordingly. This guide explains how to give Judges permissions to Awards and specific Categories.

Important Note – For the API Name field to be displayed, the Award must be Active.