Authentication

Uplynk provides three types of APIs with different capabilities and design patterns:

  1. v2 APIs – Legacy APIs using RPC-style design for core platform functions.
  2. v4 APIs – Modern RESTful APIs supporting expanded functionality and HTTP methods.
  3. v5 APIs – RESTful APIs at https://api.uplynk.com/v5.

All three accept the signed msg and sig mechanism (Integration Keys) described below. v5 APIs also accept Scoped API Keys, sent as a Bearer token in the Authorization header; see v5 APIs: Scoped API Keys.


API Types Comparison

Featurev2 APIsv4 APIs
HTTP MethodsGET, POST onlyGET, POST, PATCH, DELETE
Base Endpointhttps://services.uplynk.com/api2/https://services.uplynk.com/api/v4/
Authentication LocationQuery string parameters (msg and sig)Query string parameters (msg and sig)
Data LocationAll parameters encoded in the msg parameterAuthentication in query string, operation data in JSON body
URL Structure/api2/[resource]/[action]?msg=[encoded]&sig=[signature]/api/v4/[resource]/[id]?msg=[encoded]&sig=[signature]
Message ContentContains all request parametersContains only authentication data (_owner, _timestamp)
Content-TypeN/A (no body)application/json for requests with bodies
API Design StyleRPC-style with action verbsRESTful with resource identifiers

v5 APIs differ from both:

Featurev5 APIs
HTTP MethodsGET, POST, PATCH, DELETE
Base Endpointhttps://api.uplynk.com/v5/
AuthenticationAuthorization: Bearer <jwt> with a Scoped API Key, or msg and sig query parameters with an Integration Key
Data LocationOperation data in the JSON body
Content-Typeapplication/json for requests with bodies
ErrorsHTTP status code with an application/problem+json (Problem Details) body

v5 APIs: Scoped API Keys

Send a JWT created from a Scoped API Key in the Authorization header:

GET /v5/creatives HTTP/1.1
Host: api.uplynk.com
Authorization: Bearer <jwt>

The JWT must include:

ClaimValue
auduplynk:api. A token without this audience is rejected.
subYour Workspace ID.
scpThe scopes granted to the key. It must include one of the scopes listed on each endpoint's reference page, for example video.services.creatives:read.
iatWhen the token was created (Unix timestamp).
expWhen the token expires (Unix timestamp).

Sign the token with ES256 using the private key (PRIVATE_B64) and key ID (KID) from the .env file you download when you create the key; SUB in the same file is your Workspace ID. For the full list of scopes and claims, see Scoped API Keys.

The example needs pip3 install pyjwt cryptography requests python-dotenv (PyJWT needs cryptography for ES256), and the .env file in the same directory.

import base64, time
from os import getenv

import jwt  # PyJWT
import requests
from dotenv import load_dotenv

load_dotenv()
PRIVATE_KEY = base64.b64decode(getenv("PRIVATE_B64"))

def call_v5_api(path, scopes, method="GET", body=None):
    """scopes must include one of the endpoint's required scopes, e.g. :write for POST/PATCH/DELETE."""
    now = int(time.time())
    token = jwt.encode(
        {"aud": "uplynk:api", "sub": getenv("SUB"), "scp": scopes, "iat": now, "exp": now + 300},
        key=PRIVATE_KEY,
        algorithm="ES256",
        headers={"kid": getenv("KID")},
    )
    response = requests.request(
        method,
        f"https://api.uplynk.com/v5{path}",
        headers={"Authorization": f"Bearer {token}"},
        json=body,
    )
    response.raise_for_status()
    return response.json()

creatives = call_v5_api("/creatives", ["video.services.creatives:read"])
created = call_v5_api("/creatives", ["video.services.creatives:write"], "POST", {"title": "Spring promo"})

v5 with an Integration Key

v5 APIs also accept msg and sig, signed exactly as for v4 APIs: msg contains only _owner and _timestamp, and request data goes in the JSON body. Use https://api.uplynk.com/v5/... as the URL.


Authentication

Both API types use the same authentication mechanism. Each request requires:

ParameterDescription
_ownerYour Workspace ID (found in Settings).
_timestampThe Unix timestamp (UTC) when the request is created.
msgA Base64-encoded JSON object containing the authentication parameters (and data for v2 APIs).
sigAn HMAC-SHA256 digital signature, generated using your API key and the msg parameter.

Locating Your API Credentials

  1. Workspace ID – Found under Settings in the Uplynk CMS.
  2. API Key – Found under Integration Keys in the CMS.

Request Structure By API Type

v2 API Requests (All Data in Message)

For v2 APIs, all parameters are included in the encoded msg parameter:

  1. Create a JSON object with:
    • _owner – Your Workspace ID
    • _timestamp – Current Unix timestamp
    • All request-specific parameters
  2. Compress and encode this object to create the msg parameter
  3. Sign the encoded msg to create the sig parameter
  4. Send both as URL parameters

Example v2 GET Request:

https://services.uplynk.com/api2/asset/list?msg=eNoFwUkOgCAMAMC%2F9MyBpVLLZ0jFkpCIGiXxYPy7My%2Fk49n1ggRF0dVo61wXi8xRVlYRKYEmKiwIBvJoXe8h%2FYTkCC3F4NkZ2FpvA5L%2FfsDdF4A%3D&sig=4c585dc7ca70be3ee33852500354feca9ac896122f6910b874214b9624a0dfa4

v4 API Requests (Data in Body)

For v4 APIs, only authentication parameters go in the encoded msg:

  1. Create a JSON object with only:
    • _owner – Your Workspace ID
    • _timestamp – Current Unix timestamp
  2. Compress and encode this object to create the msg parameter
  3. Sign the encoded msg to create the sig parameter
  4. Send both as URL parameters
  5. Send request-specific data in the request body as JSON

Example v4 PATCH Request:

URL:
https://services.uplynk.com/api/v4/audiences/da3114eedfdf499fb7fb38a21614ec40?msg=eJwFwTEOgCAMAMC%2FdHYooVLKZ0itJXFAjZI4GP%2Fu3Qv1eHa%2FoIA5hZaw5bYgiSRdxVXVIs9sogQT1LF1v4f2E0pgQk4xZ%2Fx%2B5PYUiQ%3D%3D&sig=79dfaf6019f3fe0bfe68ad21a33114e769956abedaa2815d3919572a0e30ae9a

Request Body:
{
  "country_codes": ["GB", "ZA"]
}

Step-by-Step Guide to Creating Requests

1. Encoding the Message (msg)

For all APIs, you need to create and encode the msg parameter:

// Create message object
const msg = {
  _owner: "your_user_id",
  _timestamp: Math.floor(Date.now() / 1000)
};

// For v2 APIs, include all parameters here
if (isV2Api) {
  Object.assign(msg, requestSpecificParams);
}

// Compress and encode
const msgString = JSON.stringify(msg);
const compressed = zlib.deflate(msgString, { level: 9 });
const encodedMsg = base64Encode(compressed);

2. Generating the Signature (sig)

// Create HMAC-SHA256
const sig = hmacSha256(encodedMsg, "your_api_key");

3. Constructing the Request

For v2 APIs:

const url = `https://services.uplynk.com/api2/resource/action?msg=${encodedMsg}&sig=${sig}`;
// Make GET or POST request to this URL (no body)

For v4 APIs:

const url = `https://services.uplynk.com/api/v4/resource/id?msg=${encodedMsg}&sig=${sig}`;
const headers = { "Content-Type": "application/json" };
const body = JSON.stringify(requestSpecificParams);
// Make request with appropriate method and JSON body

Code Samples

Python (Handles Both v2 and v4 APIs)

import base64, hashlib, hmac, json, time, urllib.parse, zlib
import requests

def call_v2_api(uri, **params):
    """Call v2 API with all parameters in the msg."""
    user_id = "your_user_id"
    api_key = "your_api_key"
    
    # Include all params in the message
    msg = {
        "_owner": user_id,
        "_timestamp": int(time.time()),
        **params
    }
    
    # Encode and sign
    msg_json = json.dumps(msg)
    msg_compressed = zlib.compress(msg_json.encode(), level=9)
    msg_b64 = base64.b64encode(msg_compressed).decode()
    sig = hmac.new(api_key.encode(), msg_b64.encode(), hashlib.sha256).hexdigest()
    
    # Make request (all in URL, no body)
    url = f"https://services.uplynk.com{uri}"
    payload = dict(msg=msg_b64, sig=sig)
    response = requests.post(url, data=payload)
    return response.json()

def call_v4_api(uri, method, body=None):
    """Call v4 API with auth in msg and data in the request body."""
    user_id = "your_user_id"
    api_key = "your_api_key"
    
    # Only auth params in message
    msg = {
        "_owner": user_id,
        "_timestamp": int(time.time())
    }
    
    # Encode and sign
    msg_json = json.dumps(msg)
    msg_compressed = zlib.compress(msg_json.encode(), level=9)
    msg_b64 = base64.b64encode(msg_compressed).decode()
    sig = hmac.new(api_key.encode(), msg_b64.encode(), hashlib.sha256).hexdigest()
    
    # Make request (auth in URL, data in body)
    url = f"https://services.uplynk.com{uri}"
    params = dict(msg=msg_b64, sig=sig)
    headers = {"Content-Type": "application/json"} if body else None
    
    response = requests.request(
        method=method,
        url=url,
        params=params,
        json=body,  # Will be sent as JSON in body
        headers=headers
    )
    return response.json()

# Example v2 API call
assets = call_v2_api("/api2/asset/list", limit=10)

# Example v4 API call
audience = call_v4_api(
    "/api/v4/audiences/da3114eedfdf499fb7fb38a21614ec40",
    "PATCH",
    {"country_codes": ["GB", "ZA"]}
)

JavaScript

const crypto = require("crypto");
const zlib = require("zlib");
const fetch = require("node-fetch");

async function callUplynkApi(uri, method, params, isV2) {
    const USER_ID = "your_user_id";
    const API_KEY = "your_api_key";
    
    // Create message object (auth params only for v4)
    const msg = { 
        _owner: USER_ID, 
        _timestamp: Math.floor(Date.now() / 1000)
    };
    
    // For v2, include all params in message
    if (isV2) {
        Object.assign(msg, params);
    }
    
    // Encode and sign
    const msgString = JSON.stringify(msg);
    const compressed = zlib.deflateSync(msgString, { level: 9 });
    const base64Msg = compressed.toString("base64");
    const sig = crypto.createHmac("sha256", API_KEY).update(base64Msg).digest("hex");
    
    // Create URL with auth params
    const baseUrl = "https://services.uplynk.com";
    const url = new URL(baseUrl + uri);
    url.searchParams.append("msg", base64Msg);
    url.searchParams.append("sig", sig);
    
    // Set up request options
    const options = {
        method: method,
        headers: {}
    };
    
    // For v4, add body if not GET/DELETE
    if (!isV2 && params && method !== "GET" && method !== "DELETE") {
        options.body = JSON.stringify(params);
        options.headers["Content-Type"] = "application/json";
    }
    
    // Make request
    const response = await fetch(url.toString(), options);
    return await response.json();
}

// Example v2 API call
callUplynkApi("/api2/asset/list", "GET", { limit: 10 }, true)
    .then(data => console.log("V2 result:", data));

// Example v4 API call
callUplynkApi(
    "/api/v4/audiences/da3114eedfdf499fb7fb38a21614ec40",
    "PATCH", 
    { country_codes: ["GB", "ZA"] }, 
    false
).then(data => console.log("V4 result:", data));

Error Handling

v5 APIs

v5 APIs report errors with the HTTP status code and a Problem Details body (application/problem+json). Authentication failures use the same format.

FieldDescription
typeA URI identifying the kind of error.
titleThe HTTP reason, for example Unauthorized.
statusThe HTTP status code, for example 401.
detailA human-readable explanation of this error.
instanceThe request path.
errorsWhen present, a list of {source, detail} entries, one per problem.

v2 and v4 APIs

v2 and v4 API responses include an error field indicating success or failure:

Error CodeDescription
0Success
1Error (see msg for details)

Example Error Responses

Invalid Parameter:

{
  "msg": ["Unrecognized parameter: allowed_play."],
  "error": 1
}

Invalid Value:

{
  "msg": ["track_type is not valid: Values allowed are ['SD', 'HD', 'AUDIO', 'UHD1', 'UHD2', 'ALL']"],
  "error": 1
}

Resource Not Found:

{
  "msg": ["DRM Config not found."],
  "error": 1
}

Summary

  1. Choose API Version:

    • v2 APIs include all data in the message
    • v4 APIs include data in the body
  2. Authentication:

    • Always required: msg (encoded) and sig (signature) in query string
    • v2: Message contains all parameters
    • v4: Message contains only auth parameters
  3. Request Structure:

    • v2: GET/POST to /api2/resource/action
    • v4: GET/POST/PATCH/DELETE to /api/v4/resource/id
  4. Sending Data:

    • v2: All data encoded in msg parameter
    • v4: Data sent as JSON in request body

For further details, refer to the specific API documentation sections.