Uplynk API, emulated
This site documents an emulator of the Uplynk video platform's developer APIs, running on Cloudflare at services.l3ddash.com and content.l3ddash.com. It answers the same signed calls, in the same shapes, as services.uplynk.com and content.uplynk.com, and serves real HLS for a small sandbox catalog.
It exists so that applications can be built against Uplynk before having an Uplynk account. Code written against it should move to the real service by changing two base URLs, an owner ID and an API key. The video portals on this domain already work that way: every catalog read they make is a signed api2 call.
An independent project, built from Uplynk's public developer documentation. Not affiliated with or endorsed by Uplynk.
Quick start
This is the api2 client from the Uplynk Developer Center, unchanged except for the root URL and the credentials, which are this site's public sandbox account:
The same code with https://services.uplynk.com and your own user ID and API key talks to Uplynk. The repository's uplynk/smoke_test.py runs 19 checks this way, covering assets, libraries, signatures, signed playback, AssetInfo, Preplay and hosted players.
The Uplynk model
- Asset
- A piece of on-demand content. Its ID is 32 hexadecimal characters (the CMS calls it the GUID).
descis the asset's name; there is no separate description field. - External ID
- Your own identifier for an asset, unique only by convention: letters, digits,
-and_. Playback and API calls can use it in place of the asset ID, qualified by the owner's user ID. - Slices and rays
- Uplynk cuts content into roughly 4-second slices (4.096 s on the real service) and encodes each at several bitrates, called rays and named by letter from the lowest. AssetInfo reports
slice_dur,max_sliceand the ray bitrates asrates. - Library
- A flat, shareable group of assets. There are no nested folders, and libraries don't order their assets.
- Metadata
metais a free-form dictionary on each asset. It carries what other platforms model as fields: descriptions, tags, ratings, sort order.- Owner
- Each account has a 32-character user ID. Signed API messages carry it as
_owner, external-ID URLs include it, and tokens for external IDs carry it asoid. - Playback token
- Assets require a signed playback URL by default (
require_drm: 1). The signature is an HMAC of the query string with your API key, so it has to be made on a server.
Coming from Vimeo
| Vimeo | Uplynk |
|---|---|
| video | asset |
| folder / project | library (flat) |
name, description | desc, plus meta for anything else |
| tags, custom fields | meta |
player_embed_url | embed_player_url (/player5/<token>.html) |
pictures.sizes | poster_url, thumb_url, AssetInfo thumbs and thumb_prefix |
| text tracks | captions inside the HLS/DASH stream, and ttml_url |
| Bearer token per request | HMAC-signed message per request |
Hosts
| Uplynk | Emulator | Serves |
|---|---|---|
services.uplynk.com/api2/… | services.l3ddash.com/api2/… | The original management API |
services.uplynk.com/api/v4/… | services.l3ddash.com/api/v4/… | The versioned API |
content.uplynk.com | content.l3ddash.com | Manifests, AssetInfo, Preplay, hosted players |
cf.cdn.uplynk.com, content-<zone>.uplynk.com | content.l3ddash.com/slices/…, /session/… | Segments, posters, MP4s, per-session playlists. These URLs only ever arrive inside responses and manifests. |
Both emulator hosts send CORS headers, so the console on this page calls them directly from your browser.
Authentication
There are no bearer tokens or sessions. Every call carries a message and its signature:
- Put the call's parameters in a JSON object and add
_owner(your user ID) and_timestamp(Unix seconds). msg= base64( zlib-compress( JSON ) ). The reference client compresses at level 9; any zlib stream is accepted.sig= hex( HMAC-SHA256( API key,msg) ). The signature covers the base64 text exactly as sent.- api2: POST
msgandsigas a form body. Uplynk's reference pages write these calls asGET, and the emulator accepts the pair in the query string too, but the reference client POSTs.
v4:msgandsiggo in the query string and sign only_ownerand_timestamp; the call's parameters are a JSON body.
The emulator rejects a message whose _timestamp is more than 300 seconds from its clock, as a replay guard. Uplynk's docs don't state their window.
Signature inspector
Type parameters and watch the message being built, using the sandbox credentials. Everything runs in your browser.
Node.js
Responses and errors
Every response has an error field: 0 for success, 1 for failure with a msg explaining why. api2 gives msg as a string; v4 gives a list of strings, as in Uplynk's versioned-API examples.
{"error": 1, "msg": "Asset not found"}
{"error": 1, "msg": ["desc: This field is required."]}
Like api2, the emulator reports invalid parameters with HTTP 200 and error: 1. A bad signature, unknown owner or stale timestamp gets HTTP 403. A call to an Uplynk endpoint the emulator doesn't implement gets 404 and says so.
Sandbox account
These credentials are public. Calls made with the sandbox key run in full, including validation, but save nothing: updates, deletes and new libraries return what the result would be, and the response carries X-Uplynk-Emulator-Mode: sandbox.
User ID (_owner) | … |
|---|---|
| Sandbox API key | … |
| Services root | … |
| Content root | … |
Catalog
Seven assets in three libraries. Six require a token for playback; EntPEP Explainer doesn't, so you can compare.
API reference
Each call below is documented by Uplynk and implemented here. Try it loads the call into the console.
Playback URLs
| Plays | URL |
|---|---|
| An asset | /<asset_id>.m3u8 |
| An asset by external ID | /ext/<owner_id>/<external_id>.m3u8 |
| Several assets back to back | /<id1>,<id2>/multiple.m3u8 |
| Several by external ID | /ext/<owner_id>/<e1>,<e2>/multiple.m3u8 |
On the content host. Uplynk also serves .mpd (DASH), playlists, live channels and live events; the emulator serves HLS for assets only.
Query parameters
start, stop | Play only part of an asset, in seconds. The manifest keeps every slice that overlaps the window. |
rates=lo-hi | Keep rays whose average bitrate is in the range, in kbps (e.g. rates=150-500). |
resolutions=lo-hi | Keep rays whose height is in the range (e.g. resolutions=0-720). |
tc, exp, rn, ct, cid / eid + oid, sig | The playback token, described next. |
Signed URLs and token builder
When an asset has require_drm: 1, its playback URL must carry a token. Append these parameters, then sign:
tc=1 | Token algorithm version. |
exp | Expiry in Unix seconds. Keep it short, but at least 10 seconds ahead to allow for clock drift. |
rn | A random number, so signatures don't repeat. |
ct | Content type: a asset, c channel, e event, p playlist. |
cid | The content's ID; or instead eid (external ID) plus oid (your user ID). |
sig | Last: hex( HMAC-SHA256( API key, everything after ? up to &sig ) ). |
Sign on a server: anyone holding the API key can sign any URL. Uplynk's hosted embed and test players sign for you, which is why they are convenient for demos and risky to share.
Manifests
A master playlist lists one variant per ray, plus a WebVTT subtitle group when the asset has captions. As on Uplynk, a mid-quality ray comes first, which is where players start, and each variant is preceded by a private #UPLYNK-MEDIA0 tag (WIDTHxHEIGHTxFPS,profile-level,audio).
#EXTM3U
#EXT-X-VERSION:4
#EXT-X-INDEPENDENT-SEGMENTS
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",NAME="English",LANGUAGE="en",AUTOSELECT=YES,DEFAULT=NO,URI="…/session/subs.m3u8?…"
#UPLYNK-MEDIA0:1280x720x30,high-31,0x0
#EXT-X-STREAM-INF:RESOLUTION=1280x720,BANDWIDTH=557580,AVERAGE-BANDWIDTH=395303,CODECS="avc1.64001f",FRAME-RATE=30.000,SUBTITLES="subs"
…/session/c.m3u8?…
Variant playlists start with #UPLYNK-SEGMENT: <asset_id>,<first slice>,segment, as Uplynk's do, and address slices by byte range inside one MPEG-TS file per ray. Several assets are joined with #EXT-X-DISCONTINUITY.
The variant and subtitle playlist URLs are signed by the emulator and expire after 24 hours, so a token check on the master playlist can't be skipped by requesting a variant directly. Uplynk does the same job with playback sessions (pbs) and AES-128 segment keys; the emulator doesn't encrypt segments.
AssetInfo
GET content/player/assetinfo/<asset_id>.json: the public metadata a player shows. No token is needed. Fields follow the real service: asset, external_id, owner, desc, duration, slice_dur, max_slice, rates (kbps), aspect_ratio, meta, poster_url, default_poster_url, thumbs and thumb_prefix, storage_partitions, tv_rating, movie_rating, rating_flags, boundary_details, ad_data, audio_only, is_ad.
Preplay
GET content/preplay/<asset_id>.json (or /preplay/ext/<owner>/<external_id>.json) starts a playback session. It takes the same token as the playback URL and returns:
{
"ads": {"breakOffsets": [], "breaks": [], "placeholderOffsets": []},
"playURL": "https://content.l3ddash.com/preplay2/<asset_id>/<sid>.m3u8?…",
"prefix": "https://content.l3ddash.com",
"sid": "<session id>",
"drm": {"required": false}
}
On Uplynk, Preplay is where server-side ad insertion, VAST/VPAID data and Studio DRM license URLs come in. The emulator returns no ad breaks; playURL plays the content directly.
Hosted players
Each asset has an embed_player_url and one or more test_players at content/player5/<token>.html. Hosted players sign their own playback URL, so they play assets that require tokens. asset/update with embed_player_url or test_player_url set mints new ones. The emulator's player is hls.js (native HLS on Safari); append #t=30s to start 30 seconds in and ?autoplay=1 to start playing.
Captions
Uplynk carries captions inside the stream: CEA-608/708 is preserved and can be converted to WebVTT, embedded subtitle text becomes WebVTT, and a sidecar TTML file becomes both. The emulator serves captions the same way, as a segmented WebVTT subtitle rendition aligned to the video with X-TIMESTAMP-MAP, and as the TTML file at the asset's ttml_url. The portal's transcript search reads that TTML.
API console
Signs a call in your browser and sends it to the emulator. Each step of the signature is shown. The sandbox key is filled in; if you have the full key, paste it to make changes that persist. Keys never leave your browser except as signatures.
What is emulated
| Area | Status | Notes |
|---|---|---|
api2 signing (msg/sig) | Emulated | zlib + base64 + HMAC-SHA256, form body or query string |
| v4 signing | Emulated | Query-string signature, JSON body |
| Asset API | Emulated | get, list, update, delete, changes. Not: getframe, getthumbs |
| Library API | Emulated | get, list, update, assets, assets/add, assets/remove; v4 create |
| Token API | Emulated | token/checkurl, with Uplynk-style notes |
| Signed playback URLs | Emulated | tc, exp, rn, ct, cid, eid+oid, sig. iph (IP hash) is accepted but not checked |
| HLS playback | Emulated | Four rays, 4.1 s slices, WebVTT captions, start/stop, rates, resolutions, multiple |
| AssetInfo, Preplay, hosted players | Emulated | No ads, no DRM; no per-slice thumbnails yet |
| DASH | Not yet | .mpd returns 404 |
| Ads and SSAI, Ping | Not yet | Preplay returns empty ad data |
| Studio DRM, segment encryption | Not yet | require_studio_drm is stored only |
| Live channels, events, slicers, schedules, blackouts | Not yet | Calls return 404 naming the endpoint |
| Cloud Slicer (ingest), clips, VLP, syndication, statistics | Not yet | The catalog is seeded from encoded files |
Field notes
Details from the Uplynk Developer Center that are easy to miss, and that shaped the emulator.
- The reference pages and the reference client disagree on the method. Endpoint pages say
GET /api2/asset/get; theCall()helper POSTs a form body. Clients should POST. - The two API generations sign differently. api2 puts every parameter inside the signed
msg. v4 signs only_ownerand_timestampand sends the parameters as JSON, unsigned. A v4 client that signs its body the api2 way gets a signature error. - Error shapes differ too: api2
msgis a string, v4msgis a list. descmeans name. Asset and librarydescis the display name; descriptions and tags belong inmeta.- Times are milliseconds in API responses (
created,lastmod,asset/changes) and seconds in tokens (exp) and signed messages (_timestamp). - External IDs aren't checked for uniqueness. When two assets share one, Uplynk plays an arbitrary match. The
_replace:prefix at slicing time reuses an external ID for a re-encode. asset/changeskeeps deletions for a short window, about six hours, so a sync job has to poll at least that often to see every delete. The response includes the change atstart, so the next call repeats the last change.searchonasset/listreached end of life on 2023-03-31;queryreplaced it and matches any keyword.- Tokens are content-bound.
cidmust match the URL's content,ctits type, and for external IDsoidis always your own user ID, even for content in a library someone shared with you, while the URL path names the sharing account. - Signed URLs should expire quickly but not too quickly: at least 10 seconds ahead, because viewers' clocks drift.
token/checkurlis a development tool. Uplynk warns that calling it for every token in production can lead to charges or termination.- Several assets in one URL (
/multiple.m3u8) must total under 16 hours, belong to one account, appear once each and be finished encoding. Uplynk suggests a virtual linear playlist instead, for faster starts and better ad fill. - Preplay's
playURLis opaque. Uplynk reserves the right to change its format; players use it as given. - A real master manifest (public demo asset
42cada5a…) lists a 960x540 ray first, then 720p, 144p, 234p and 360p, all H.264 at 30 fps with AAC audio, plus an I-frame trick-play playlist. Its variants use 4.096 s TS slices oncf.cdn.uplynk.com, each AES-128 encrypted, with key URLs on the session's zone host.