Non-Protected Content

Non-Protected Content (Clear Delivery)

🎞️

Clear delivery lets a project ingest and serve selected videos without DRM, using the exact same upload, transcoding and webhook pipeline as protected content. It is designed for platform-managed promotional assets such as user-created trailers.

Overview

By default, every piece of content in a Media Protection project is packaged with DRM. When clear delivery is enabled for a project, individual contents can be created with protectionMode: "clear". These contents are:

  • Uploaded and imported through the same endpoints as protected content.
  • Transcoded into the same quality ladder, producing HLS, DASH and, when available, a progressive rendition — all unencrypted.
  • Served from your project's custom subdomain through signed URLs that your backend can generate offline (no API call required).
  • Still fully covered by EngageKit: snapshots, previews and auto-generated trailers are produced as usual.

Key properties:

PropertyBehavior
protectionMode"drm" (default when absent) or "clear". Immutable after creation.
Input typesVideo and audio only. Images are rejected for clear contents, even if image processing is enabled.
Playback tokensNot applicable. generatePlaybackToken returns 409 for clear contents.
PlayerBring your own (hls.js, Shaka, dash.js, native HLS or a plain <video> tag). The Fastevo Player is DRM-only.
Forensic watermarkingNot applied. Clear content is downloadable by anyone holding a valid URL.
⚠️

Clear content is not protected. Anyone with a valid signed URL can watch and download it until the URL expires. Only use clear delivery for content you are comfortable distributing openly, such as trailers and teasers.

To get a playable URL after processing finishes, either request a signed URL from the API or sign it in your own backend. Clear content does not use generatePlaybackToken or the Fastevo Player.

Enabling Clear Delivery for a Project

Clear delivery is disabled by default and must be enabled per project.

In the Dashboard, open Project Settings → General → Unprotected content, enable Allow unprotected content creation, and save the change. When this setting is disabled, clear mode is not offered for new uploads or imports, and the overflow menu omits Create unprotected version when no linked clear variant exists. Existing clear contents and useful linked-variant actions remain available.

MethodEndpointDescription
GEThttps://api.fastevo.net/api/v1/projects/mediaProtection/configurations/general/clearDeliveryReturns the current configuration.
PUThttps://api.fastevo.net/api/v1/projects/mediaProtection/configurations/general/clearDeliveryUpdates the configuration.

Request Body (PUT)

{
  "isCreationEnabled": true,
  "maxTokenTtlSeconds": 21600
}
FieldTypeDescription
isCreationEnabledbooleanGates the creation of new clear contents. Disabling it later does not interrupt the serving of existing clear contents; it only blocks new creations.
maxTokenTtlSecondsnumberMaximum lifetime of a delivery URL, in seconds. 60 to 604800 (7 days). Default 21600 (6 hours).

Clear delivery requires the project to use the tenant deployment type (the default for new projects). The endpoint returns 409 otherwise.

Creating Clear Content

Add protectionMode: "clear" to the regular creation call — upload, multipart upload and URL import all support it:

POST https://api.fastevo.net/api/v1/projects/mediaProtection/contents/upload
Authorization: Bearer <token>
Content-Type: application/json
 
{
  "title": "Trailer - My Video",
  "protectionMode": "clear",
  "multipartUpload": true
}

Rules:

  • Omitting protectionMode (or sending "drm") keeps the default protected behavior — existing integrations continue to work unchanged.
  • Sending "clear" when the project gate is disabled returns 403.
  • protectionMode is immutable: it cannot be changed on update or reprocess. To reuse a retained original, create an independent protected or non-protected variant.
  • Image files are rejected for clear contents during processing.

Reading Clear Content

Content Object

The public content object of a clear content includes two additional fields:

{
  "_id": "6a0000000000000000000001",
  "title": "Trailer - My Video",
  "status": "ready",
  "protectionMode": "clear",
  "delivery": {
    "activeGenerationId": "gen-6a0000000000000000000002",
    "outputContentType": "video",
    "sources": [
      { "format": "hls", "mimeType": "application/vnd.apple.mpegurl", "relativePath": "master.m3u8" },
      { "format": "dash", "mimeType": "application/dash+xml", "relativePath": "master.mpd" },
      { "format": "progressive", "mimeType": "video/mp4", "relativePath": "progressive/main.mp4" }
    ]
  }
}
FieldDescription
delivery.activeGenerationIdThe identifier of the current packaging generation. It changes on every reprocess, which automatically invalidates previously signed URLs.
delivery.outputContentType"video" or "audio". Needed to build delivery URLs.
delivery.sources[]Every available format with its relativePath — everything your backend needs to sign URLs offline. progressive is included only when the active generation has a progressive rendition; its MIME type is video/mp4 for video or audio/mp4 for audio. Use the returned path instead of assuming a filename.

Content list items include protectionMode as well, so you can distinguish clear contents without fetching each one.

Webhook

The ready webhook notification for a clear content additively includes:

{
  "protectionMode": "clear",
  "clearDeliveryGenerationId": "gen-6a0000000000000000000002",
  "delivery": {
    "generationId": "gen-6a0000000000000000000002",
    "outputContentType": "video",
    "sources": [
      { "format": "hls", "mimeType": "application/vnd.apple.mpegurl", "relativePath": "master.m3u8" },
      { "format": "dash", "mimeType": "application/dash+xml", "relativePath": "master.mpd" },
      { "format": "progressive", "mimeType": "video/mp4", "relativePath": "progressive/main.mp4" }
    ]
  }
}

After a reprocess, a new ready notification carries the new generationId: regenerate your URLs when you receive it.

⚠️

A reprocess is not a seamless swap. The previous output is removed before the new one is uploaded, so between those two moments the old URLs stop resolving, and a viewer already playing will see the stream fail. The generationId in the path versions the output — it does not keep the previous generation alive alongside the new one.

Plan reprocesses for a maintenance window if the content is being watched, and treat any ready notification as "the previous URLs are already gone".

Delivery URLs

Clear content is served from your project's custom subdomain with the authorization token embedded in the URL path:

https://{yourSubdomain}/clear/v1/{contentId}/{outputContentType}/{generationId}/s/{expires}/{signature}/{relativePath}
SegmentDescription
contentIdThe Fastevo content ID (24 hex chars).
outputContentTypevideo or audio (from delivery.outputContentType).
generationIdThe active generation (from delivery.activeGenerationId).
expiresUnix timestamp (seconds) when the URL stops working. Bounded by maxTokenTtlSeconds.
signatureHMAC-SHA256 signature, lowercase hex (see below).
relativePathAny relativePath from delivery.sources[] — e.g. master.m3u8.

Because the token lives in the path, HLS and DASH manifests — which reference their segments with relative URLs — inherit the authorization automatically. One signed URL for master.m3u8 covers every playlist, segment and byte-range request underneath it. No player configuration, request interception or query-string forwarding is needed. This works out of the box with hls.js, Shaka, dash.js, Safari/iOS native HLS, and plain <video src> for the progressive MP4.

A signature authorizes the entire generation of that content: the same expires/signature pair is valid for any relativePath of that generation. Sign once per playback session, not once per file.

Signing URLs Yourself

Your backend can generate delivery URLs offline using the project's Token Signing Key (the same secret used for playback tokens and EngageKit signing — available in the panel under API settings).

The Token Signing Key is not the project API key. Keep the requested lifetime within the project's maxTokenTtlSeconds; the CDN rejects an expiration beyond that limit.

The string to sign is:

fastevo-clear-delivery-v1\n{contentId}\n{outputContentType}\n{generationId}\n{expires}

The signature is HMAC-SHA256(tokenSigningKeySecret, stringToSign), hex-encoded, lowercase.

⚠️

Sign server-side only. Never ship the Token Signing Key to a browser or mobile app.

Node.js

const crypto = require("crypto");
 
function buildClearDeliveryUrl({ subdomain, contentId, outputContentType, generationId, ttlSeconds, tokenSigningKeySecret, relativePath }) {
  const expires = Math.floor(Date.now() / 1000) + ttlSeconds;
  const stringToSign = ["fastevo-clear-delivery-v1", contentId, outputContentType, generationId, String(expires)].join("\n");
  const signature = crypto.createHmac("sha256", tokenSigningKeySecret).update(stringToSign).digest("hex");
  return `https://${subdomain}/clear/v1/${contentId}/${outputContentType}/${generationId}/s/${expires}/${signature}/${relativePath}`;
}

PHP

function buildClearDeliveryUrl(
    string $subdomain,
    string $contentId,
    string $outputContentType,
    string $generationId,
    int $ttlSeconds,
    string $tokenSigningKeySecret,
    string $relativePath
): string {
    $expires = time() + $ttlSeconds;
    $stringToSign = implode("\n", [
        "fastevo-clear-delivery-v1",
        $contentId,
        $outputContentType,
        $generationId,
        (string) $expires,
    ]);
    $signature = hash_hmac("sha256", $stringToSign, $tokenSigningKeySecret);
 
    return "https://{$subdomain}/clear/v1/{$contentId}/{$outputContentType}/{$generationId}/s/{$expires}/{$signature}/{$relativePath}";
}

Test Vector

Use this vector to validate your implementation:

InputValue
Keytest-secret-key
contentId6a0000000000000000000001
outputContentTypevideo
generationIdgen-6a0000000000000000000002
expires1800000000
Expected signaturecfa2390049a1f3f15f7a5ef538a9a442105ae3becfbfbeb15340cf8b94337d6a

Requesting Signed URLs from the API

This is the simplest option if you do not want to implement signing. Once the content has protectionMode: "clear" and status: "ready", make this request from your backend using an active API key for the same project. You do not need to obtain or use the Token Signing Key for this option:

POST https://api.fastevo.net/api/v1/projects/mediaProtection/contents/{contentId}/generateDeliveryAuthorization
Authorization: Bearer <PROJECT_API_KEY>
Content-Type: application/json
 
{ "expiresIn": "2h" }

Response (201)

{
  "protectionMode": "clear",
  "generationId": "gen-6a0000000000000000000002",
  "expiresAt": 1800000000,
  "sources": [
    { "format": "hls", "mimeType": "application/vnd.apple.mpegurl", "url": "https://..../master.m3u8" },
    { "format": "dash", "mimeType": "application/dash+xml", "url": "https://..../master.mpd" },
    { "format": "progressive", "mimeType": "video/mp4", "url": "https://..../progressive/main.mp4" }
  ]
}

The effective TTL is min(expiresIn, maxTokenTtlSeconds). The endpoint returns 409 when the content is not clear, not ready, or has no active generation yet.

Choose the desired entry in sources by its format and pass its url to your own player. The URL is already signed: the player does not send your API key and does not need a playback token. The progressive entry is returned only when that rendition is available.

Lifecycle Notes

  • Reprocessing produces a new generation. Old URLs stop resolving as soon as the new generation is active — regenerate URLs when the ready webhook arrives.
  • Trash: sending a clear content to the trash starts file quarantine and CDN cache invalidation. Existing URLs stop working once those operations complete, even before they expire; do not treat the delete response as instantaneous revocation of cached files. Restoring the content makes the same generation servable again.
  • Long videos: sign with a TTL that covers the full expected playback duration — segment requests made after expires are rejected with 403.

Error Reference

StatusWhereMeaning
403 (CDN)Delivery URLMissing/invalid/expired signature, malformed path, or clear delivery not enabled for the tenant.
403 (API)Content creationprotectionMode: "clear" sent while the project gate is disabled.
409 (API)generateDeliveryAuthorizationContent is not clear, not ready, or has no active generation.
409 (API)generatePlaybackTokenContent is clear — playback tokens do not apply; use delivery URLs instead.
409 (API)ConfigurationProject does not use the tenant deployment type.