ClosedCast Developer Center

Build private streaming archives, not noisy video feeds.

The ClosedCast API helps families, churches, organizations, coaches, and communities preserve meaningful videos in private archives that remain organized, accessible, and ready to watch.

API design principle

ClosedCast is built for continuity. The API should help people preserve what matters, organize it clearly, share it intentionally, and return to it over time.

Private by default Organized for revisiting Built for archives No public feed required
Getting Started

Authorization

Bearer Token

How to get an API key

  1. Sign in to ClosedCast.
  2. Open Settings.
  3. Find API Access.
  4. Turn API access on.
  5. Copy your API token.

Treat your API token like a password. If you regenerate it, Zapier and other integrations using the old token must be updated.

Authorization header

Authorization: Bearer cc_live_YOUR_API_TOKEN

Standard JSON headers

Accept: application/json
Content-Type: application/json
Quick Test

Your first request

GET
curl.exe -X GET "https://closedcast.com/APIv1/Ping" ^
  -H "Authorization: Bearer YOUR_API_TOKEN"

Use Ping to confirm that your API token is working before building upload, sharing, or automation workflows.

API Reference

Endpoint matrix

These endpoints are grouped by the work people are trying to do: preserve videos, organize collections, invite members, search archives, and monitor activity.

General

GET
Ping /APIv1/Ping

Confirm API connectivity and token access.

Sample input

No request body required.

Sample output

{
  "ok": true,
  "version": "v1"
}

Sample curl

curl.exe -X GET "https://closedcast.com/APIv1/Ping" ^
  -H "Authorization: Bearer YOUR_API_TOKEN" ^
  -H "Accept: application/json"

Account

GET
Account /APIv1/Account

Return the authenticated account and organization context.

Sample input

No request body required.

Sample output

{
  "ok": true,
  "version": "v1",
  "account": {
    "TenantID": "TENANT_ID",
    "TenantName": "My Private Archive",
    "Email": "owner@example.com"
  }
}

Sample curl

curl.exe -X GET "https://closedcast.com/APIv1/Account" ^
  -H "Authorization: Bearer YOUR_API_TOKEN" ^
  -H "Accept: application/json"

Video

GET
Videos /APIv1/Videos

List videos in the authenticated account.

Sample input

No request body required.

Sample output

{
  "ok": true,
  "version": "v1",
  "count": 1,
  "videos": [
    {
      "VideoID": "VIDEO_ID",
      "CategoryID": "CATEGORY_ID",
      "CategoryName": "Memories",
      "Title": "Family Video",
      "Description": "A private archive video",
      "ThumbnailUrl": "https://videodelivery.net/VIDEO_UID/thumbnails/thumbnail.jpg",
      "DurationSeconds": 6,
      "Status": "ready",
      "IsReady": true,
      "Active": true
    }
  ]
}

Sample curl

curl.exe -X GET "https://closedcast.com/APIv1/Videos" ^
  -H "Authorization: Bearer YOUR_API_TOKEN" ^
  -H "Accept: application/json"
GET
Video(id) /APIv1/Video?id={VideoID}

Return one video by ID.

Sample input

No request body required.

Sample output

{
  "ok": true,
  "version": "v1",
  "video": {
    "VideoID": "VIDEO_ID",
    "CategoryID": "CATEGORY_ID",
    "CategoryName": "Training Videos",
    "Title": "Introduction to Private Archives",
    "Description": "",
    "Tags": [],
    "ThumbnailUrl": "https://videodelivery.net/VIDEO_UID/thumbnails/thumbnail.jpg",
    "DurationSeconds": 1956,
    "Status": "ready",
    "IsReady": true,
    "Active": true,
    "CreatedUtc": "/Date(1767225600000)/",
    "UpdatedUtc": "/Date(1767225600000)/"
  }
}

Sample curl

curl.exe -X GET "https://closedcast.com/APIv1/Video?id={VideoID}" ^
  -H "Authorization: Bearer YOUR_API_TOKEN" ^
  -H "Accept: application/json"
POST
CreateVideo /APIv1/CreateVideo

Create video metadata before upload.

Sample input

{
  "Title": "Family Memories",
  "Description": "A video worth preserving",
  "CategoryID": "CATEGORY_ID"
}

Sample output

{
  "ok": true,
  "version": "v1",
  "VideoID": "VIDEO_ID",
  "Status": "ready",
  "IsReady": true
}

Sample curl

curl.exe -X POST "https://closedcast.com/APIv1/CreateVideo" ^
  -H "Authorization: Bearer YOUR_API_TOKEN" ^
  -H "Content-Type: application/json" ^
  -H "Accept: application/json" ^
  -d "{  \"Title\": \"Family Memories\",  \"Description\": \"A video worth preserving\",  \"CategoryID\": \"CATEGORY_ID\"}"
POST
UpdateVideo /APIv1/UpdateVideo

Update title, description, category, tags, or archive metadata.

Sample input

{
  "VideoID": "VIDEO_ID",
  "Title": "Updated Title",
  "Description": "Updated description",
  "CategoryID": "CATEGORY_ID"
}

Sample output

{
  "ok": true,
  "version": "v1",
  "VideoID": "VIDEO_ID",
  "Status": "ready",
  "IsReady": true
}

Sample curl

curl.exe -X POST "https://closedcast.com/APIv1/UpdateVideo" ^
  -H "Authorization: Bearer YOUR_API_TOKEN" ^
  -H "Content-Type: application/json" ^
  -H "Accept: application/json" ^
  -d "{  \"VideoID\": \"VIDEO_ID\",  \"Title\": \"Updated Title\",  \"Description\": \"Updated description\",  \"CategoryID\": \"CATEGORY_ID\"}"
POST
UploadVideo /APIv1/UploadVideo

Upload a video file using multipart form data.

Sample input

multipart/form-data

Title=Sunday Service
Description=Uploaded file
CategoryID=CATEGORY_ID
File=@C:\path\to\video.mp4

Sample output

{
  "ok": true,
  "version": "v1",
  "VideoID": "VIDEO_ID",
  "Status": "ready",
  "IsReady": true
}

Sample curl

curl.exe -X POST "https://closedcast.com/APIv1/UploadVideo" ^
  -H "Authorization: Bearer YOUR_API_TOKEN" ^
  -F "Title=Sunday Service" ^
  -F "Description=Uploaded file" ^
  -F "CategoryID=CATEGORY_ID" ^
  -F "File=@C:\\path\\to\\video.mp4"
POST
UploadVideoFromFileUrl /APIv1/UploadVideoFromFileUrl

Upload a video from a downloadable file URL. Best for Zapier and automation.

Sample input

multipart/form-data

Title=Sunday Service
Description=Uploaded file
CategoryID=CATEGORY_ID
File=@C:\path\to\video.mp4

Sample output

{
  "ok": true,
  "version": "v1",
  "VideoID": "VIDEO_ID",
  "Status": "ready",
  "IsReady": true
}

Sample curl

curl.exe -X POST "https://closedcast.com/APIv1/UploadVideoFromFileUrl" ^
  -H "Authorization: Bearer YOUR_API_TOKEN" ^
  -F "Title=Sunday Service" ^
  -F "Description=Uploaded file" ^
  -F "CategoryID=CATEGORY_ID" ^
  -F "File=@C:\\path\\to\\video.mp4"
POST
DeleteVideo /APIv1/DeleteVideo

Delete or deactivate a video.

Sample input

{
  "VideoID": "VIDEO_ID"
}

Sample output

{
  "ok": true,
  "version": "v1",
  "VideoID": "VIDEO_ID",
  "Status": "ready",
  "IsReady": true
}

Sample curl

curl.exe -X POST "https://closedcast.com/APIv1/DeleteVideo" ^
  -H "Authorization: Bearer YOUR_API_TOKEN" ^
  -H "Content-Type: application/json" ^
  -H "Accept: application/json" ^
  -d "{  \"VideoID\": \"VIDEO_ID\"}"
GET
Playback(id) /APIv1/Playback?id={VideoID}

Return a secure playback URL for a ready video.

Sample input

No request body required.

Sample output

{
  "ok": true,
  "version": "v1",
  "VideoID": "VIDEO_ID",
  "Status": "ready",
  "IsReady": true
}

Sample curl

curl.exe -X GET "https://closedcast.com/APIv1/Playback?id={VideoID}" ^
  -H "Authorization: Bearer YOUR_API_TOKEN" ^
  -H "Accept: application/json"
GET
Download(id,mode) /APIv1/Download?id={VideoID}&mode=json

Prepare and return a secure MP4 download URL. Omit mode=json to receive a 302 redirect when ready.

Sample input

No request body required.

Sample output

{
  "ok": true,
  "version": "v1",
  "status": "ready",
  "download": {
    "VideoID": "VIDEO_ID",
    "Title": "Family Video",
    "FileName": "FamilyVideo.mp4",
    "Format": "video/mp4",
    "Url": "https://customer.cloudflarestream.com/SIGNED_TOKEN/downloads/default.mp4",
    "ExpiresUtc": "2026-07-13T18:30:00Z"
  }
}

Sample curl

curl.exe -i "https://closedcast.com/APIv1/Download?id=VIDEO_ID&mode=json" ^
  -H "Authorization: Bearer YOUR_API_TOKEN" ^
  -H "Accept: application/json"
POST
RefreshVideo(request) /APIv1/RefreshVideo

Refresh processing status from Cloudflare.

Sample input

{
  "VideoID": "VIDEO_ID"
}

Sample output

{
  "ok": true,
  "version": "v1",
  "VideoID": "VIDEO_ID",
  "Status": "ready",
  "IsReady": true
}

Sample curl

curl.exe -X POST "https://closedcast.com/APIv1/RefreshVideo" ^
  -H "Authorization: Bearer YOUR_API_TOKEN" ^
  -H "Content-Type: application/json" ^
  -H "Accept: application/json" ^
  -d "{  \"VideoID\": \"VIDEO_ID\"}"

Category / Collection

GET
Categories /APIv1/Categories

List collections for the authenticated account.

Sample input

No request body required.

Sample output

{
  "ok": true,
  "version": "v1",
  "count": 2,
  "categories": [
    {
      "CategoryID": "CATEGORY_ID",
      "Name": "Memories",
      "Active": true,
      "OfferEnabled": false,
      "CreatedUtc": "/Date(1767225600000)/",
      "UpdatedUtc": "/Date(1767225600000)/"
    }
  ]
}

Sample curl

curl.exe -X GET "https://closedcast.com/APIv1/Categories" ^
  -H "Authorization: Bearer YOUR_API_TOKEN" ^
  -H "Accept: application/json"
GET
Category(id) /APIv1/Category?id={CategoryID}

Return one collection by ID.

Sample input

No request body required.

Sample output

{
  "ok": true,
  "version": "v1",
  "category": {
    "CategoryID": "CATEGORY_ID",
    "TenantID": "TENANT_ID",
    "Name": "Memories",
    "OfferEnabled": false,
    "Active": true,
    "VideoCount": 4,
    "CreatedUtc": "/Date(1767225600000)/",
    "UpdatedUtc": "/Date(1767225600000)/"
  }
}

Sample curl

curl.exe -X GET "https://closedcast.com/APIv1/Category?id={CategoryID}" ^
  -H "Authorization: Bearer YOUR_API_TOKEN" ^
  -H "Accept: application/json"
POST
CreateCategory(request) /APIv1/CreateCategory

Create a new collection.

Sample input

{
  "Name": "Sermons"
}

Sample output

{
  "ok": true,
  "version": "v1",
  "message": "Success"
}

Sample curl

curl.exe -X POST "https://closedcast.com/APIv1/CreateCategory" ^
  -H "Authorization: Bearer YOUR_API_TOKEN" ^
  -H "Content-Type: application/json" ^
  -H "Accept: application/json" ^
  -d "{  \"Name\": \"Sermons\"}"
POST
UpdateCategory(request) /APIv1/UpdateCategory

Update collection name or settings.

Sample input

{
  "CategoryID": "CATEGORY_ID",
  "Name": "Sunday Sermons"
}

Sample output

{
  "ok": true,
  "version": "v1",
  "message": "Success"
}

Sample curl

curl.exe -X POST "https://closedcast.com/APIv1/UpdateCategory" ^
  -H "Authorization: Bearer YOUR_API_TOKEN" ^
  -H "Content-Type: application/json" ^
  -H "Accept: application/json" ^
  -d "{  \"CategoryID\": \"CATEGORY_ID\",  \"Name\": \"Sunday Sermons\"}"
POST
DeleteCategory(request) /APIv1/DeleteCategory

Delete or deactivate a collection.

Sample input

{
  "CategoryID": "CATEGORY_ID"
}

Sample output

{
  "ok": true,
  "version": "v1",
  "message": "Success"
}

Sample curl

curl.exe -X POST "https://closedcast.com/APIv1/DeleteCategory" ^
  -H "Authorization: Bearer YOUR_API_TOKEN" ^
  -H "Content-Type: application/json" ^
  -H "Accept: application/json" ^
  -d "{  \"CategoryID\": \"CATEGORY_ID\"}"
GET
GetCategoryVideos(id) /APIv1/GetCategoryVideos?CategoryID={CategoryID}

List videos in one collection.

Sample input

No request body required.

Sample output

{
  "ok": true,
  "version": "v1",
  "category": {
    "CategoryID": "CATEGORY_ID",
    "Name": "Memories"
  },
  "count": 1,
  "videos": [
    {
      "VideoID": "VIDEO_ID",
      "CategoryID": "CATEGORY_ID",
      "CategoryName": "Memories",
      "Title": "Family Video",
      "Description": "A private archive video",
      "Tags": null,
      "ThumbnailUrl": "https://videodelivery.net/VIDEO_UID/thumbnails/thumbnail.jpg",
      "DurationSeconds": 6,
      "Status": "ready",
      "IsReady": true,
      "Active": true,
      "CreatedUtc": "/Date(1767225600000)/",
      "UpdatedUtc": "/Date(1767225600000)/"
    }
  ]
}

Sample curl

curl.exe -X GET "https://closedcast.com/APIv1/GetCategoryVideos?CategoryID={CategoryID}" ^
  -H "Authorization: Bearer YOUR_API_TOKEN" ^
  -H "Accept: application/json"
GET
GetCategoryVideosByName(name) /APIv1/GetCategoryVideosByName?CategoryName={Name}

List videos by collection name.

Sample input

No request body required.

Sample output

{
  "ok": true,
  "version": "v1",
  "category": {
    "CategoryID": "CATEGORY_ID",
    "Name": "Memories"
  },
  "count": 1,
  "videos": [
    {
      "VideoID": "VIDEO_ID",
      "CategoryID": "CATEGORY_ID",
      "CategoryName": "Memories",
      "Title": "Family Video",
      "Description": "A private archive video",
      "Tags": null,
      "ThumbnailUrl": "https://videodelivery.net/VIDEO_UID/thumbnails/thumbnail.jpg",
      "DurationSeconds": 6,
      "Status": "ready",
      "IsReady": true,
      "Active": true,
      "CreatedUtc": "/Date(1767225600000)/",
      "UpdatedUtc": "/Date(1767225600000)/"
    }
  ]
}

Sample curl

curl.exe -X GET "https://closedcast.com/APIv1/GetCategoryVideosByName?CategoryName={Name}" ^
  -H "Authorization: Bearer YOUR_API_TOKEN" ^
  -H "Accept: application/json"

User

GET
Users /APIv1/Users

List account members.

Sample input

No request body required.

Sample output

{
  "ok": true,
  "version": "v1",
  "count": 1,
  "users": [
    {
      "UserID": "USER_ID",
      "Email": "owner@example.com",
      "Status": "Active",
      "FirstName": "Alex",
      "LastName": "Owner",
      "DisplayName": "Alex Owner",
      "LastLoginUtc": null,
      "CreatedUtc": "/Date(1767225600000)/",
      "UpdatedUtc": "/Date(1767225600000)/"
    }
  ]
}

Sample curl

curl.exe -X GET "https://closedcast.com/APIv1/Users" ^
  -H "Authorization: Bearer YOUR_API_TOKEN" ^
  -H "Accept: application/json"
GET
GetUser(id) /APIv1/GetUser?id={UserID}

Return one account member.

Sample input

No request body required.

Sample output

{
  "ok": true,
  "version": "v1",
  "user": {
    "UserID": "USER_ID",
    "Email": "owner@example.com",
    "Status": "active",
    "FirstName": "Alex",
    "LastName": "Owner",
    "DisplayName": "Alex Owner",
    "LastLoginUtc": null,
    "CreatedUtc": "/Date(1767225600000)/",
    "UpdatedUtc": "/Date(1767225600000)/"
  }
}

Sample curl

curl.exe -X GET "https://closedcast.com/APIv1/GetUser?id={UserID}" ^
  -H "Authorization: Bearer YOUR_API_TOKEN" ^
  -H "Accept: application/json"

Invites / Sharing

POST
SendInvite(request) /APIv1/SendInvite

Invite someone to access a video or collection.

Sample input

{
  "What": "Video",
  "WhatID": "VIDEO_ID",
  "RecipientEmail": "member@example.com",
  "RecipientName": "Member Name"
}

Sample output

{
  "ok": true,
  "version": "v1",
  "InviteID": "INVITE_ID",
  "message": "Invite processed."
}

Sample curl

curl.exe -X POST "https://closedcast.com/APIv1/SendInvite" ^
  -H "Authorization: Bearer YOUR_API_TOKEN" ^
  -H "Content-Type: application/json" ^
  -H "Accept: application/json" ^
  -d "{  \"What\": \"Video\",  \"WhatID\": \"VIDEO_ID\",  \"RecipientEmail\": \"member@example.com\",  \"RecipientName\": \"Member Name\"}"
GET
Invites /APIv1/Invites

List active and pending invites.

Sample input

No request body required.

Sample output

{
  "ok": true,
  "version": "v1",
  "count": 1,
  "invites": [
    {
      "GrantID": "GRANT_ID",
      "What": "Video",
      "WhatID": "VIDEO_ID",
      "RecipientEmail": "member@example.com",
      "RecipientName": "Member Name",
      "AssignedBy": "USER_ID",
      "Active": true,
      "PendingActivation": true,
      "ExpiresUtc": null,
      "CreatedUtc": "/Date(1767225600000)/",
      "UpdatedUtc": "/Date(1767225600000)/"
    }
  ]
}

Sample curl

curl.exe -X GET "https://closedcast.com/APIv1/Invites" ^
  -H "Authorization: Bearer YOUR_API_TOKEN" ^
  -H "Accept: application/json"
POST
RevokeInvite(request) /APIv1/RevokeInvite

Revoke access previously granted by invite.

Sample input

{
  "InviteID": "INVITE_ID"
}

Sample output

{
  "GrantID": "GRANT_ID"
}

Sample curl

curl.exe -X POST "https://closedcast.com/APIv1/RevokeInvite" ^
  -H "Authorization: Bearer YOUR_API_TOKEN" ^
  -H "Content-Type: application/json" ^
  -H "Accept: application/json" ^
  -d "{  \"InviteID\": \"INVITE_ID\"}"

Contacts

GET
Contacts /APIv1/Contacts

List contacts collected through offers or access requests.

Sample input

No request body required.

Sample output

{
  "ok": true,
  "version": "v1",
  "count": 1,
  "contacts": [
    {
      "ContactID": "CONTACT_ID",
      "Name": "Jane Smith",
      "Email": "jane.smith@example.com",
      "FirstName": "Jane",
      "LastName": "Smith",
      "Phone": "",
      "What": "Video",
      "WhatID": "VIDEO_ID",
      "AccessGrantID": "ACCESS_GRANT_ID",
      "CreatedUtc": "/Date(1767225600000)/"
    }
  ]
}

Sample curl

curl.exe -X GET "https://closedcast.com/APIv1/Contacts" ^
  -H "Authorization: Bearer YOUR_API_TOKEN" ^
  -H "Accept: application/json"
GET
Contact(id) /APIv1/Contact?id={ContactID}

Return one contact.

Sample input

No request body required.

Sample output

{
  "ok": true,
  "version": "v1",
  "count": 1,
  "contacts": [
    {
      "ContactID": "CONTACT_ID",
      "Name": "Jane Smith",
      "Email": "jane.smith@example.com",
      "FirstName": "Jane",
      "LastName": "Smith",
      "Phone": "",
      "What": "Video",
      "WhatID": "VIDEO_ID",
      "AccessGrantID": "ACCESS_GRANT_ID",
      "CreatedUtc": "/Date(1767225600000)/"
    }
  ]
}

Sample curl

curl.exe -X GET "https://closedcast.com/APIv1/Contact?id={ContactID}" ^
  -H "Authorization: Bearer YOUR_API_TOKEN" ^
  -H "Accept: application/json"
GET
ContactsForItem(itemType,itemID) /APIv1/ContactsForItem?itemType={Video|Category}&itemID={VIDEO_ID or CATEGORYID}

List contacts connected to a video or collection.

Sample input

No request body required.

Sample output

{
  "ok": true,
  "version": "v1",
  "count": 1,
  "contacts": [
    {
      "ContactID": "CONTACT_ID",
      "Name": "Jane Smith",
      "Email": "jane.smith@example.com",
      "FirstName": "Jane",
      "LastName": "Smith",
      "Phone": "",
      "What": "Video",
      "WhatID": "VIDEO_ID",
      "AccessGrantID": "ACCESS_GRANT_ID",
      "CreatedUtc": "/Date(1767225600000)/"
    }
  ]
}

Sample curl

curl.exe -X GET "https://closedcast.com/APIv1/ContactsForItem?itemType={Video|Category}&itemID={VIDEO_ID or CATEGORYID}" ^
  -H "Authorization: Bearer YOUR_API_TOKEN" ^
  -H "Accept: application/json"

Search

GET
Search(search) /APIv1/Search?q={query}

Search videos, collections, and archive metadata.

Sample input

No request body required.

Sample output

{
  "ok": true,
  "version": "v1",
  "search": "family",
  "count": 1,
  "videos": [
    {
      "VideoID": "VIDEO_ID",
      "CategoryID": "CATEGORY_ID",
      "CategoryName": "Family",
      "Title": "Family Video",
      "Description": "A private archive video",
      "Tags": ["family","vacation"],
      "ThumbnailUrl": "https://videodelivery.net/VIDEO_UID/thumbnails/thumbnail.jpg",
      "DurationSeconds": 125,
      "Status": "ready",
      "IsReady": true,
      "Active": true,
      "CreatedUtc": "/Date(1767225600000)/",
      "UpdatedUtc": "/Date(1767225600000)/"
    }
  ]
}

Sample curl

curl.exe -X GET "https://closedcast.com/APIv1/Search?q={query}" ^
  -H "Authorization: Bearer YOUR_API_TOKEN" ^
  -H "Accept: application/json"

Events

GET
Events /APIv1/ZapierEvents?eventType=some.event

Return recent API events for automation polling.

Sample input

No request body required.

Sample output

[
  {
    "id": "EVENT_ID",
    "EventID": "EVENT_ID",
    "EventType": "video.created",
    "ItemType": "Video",
    "ItemID": "VIDEO_ID",
    "ItemName": "Family Video",
    "CreatedUtc": "/Date(1767225600000)/"
  }
]

Sample curl

curl.exe -X GET "https://closedcast.com/APIv1/ZapierEvents?eventType=some.event" ^
  -H "Authorization: Bearer YOUR_API_TOKEN" ^
  -H "Accept: application/json"

Event List

The Events endpoint returns a chronological history of activity that occurs within your ClosedCast account. Automation platforms such as Zapier, Make, n8n, Power Automate, and AI agents can poll this endpoint to detect changes and trigger workflows. For example to poll for video created events call: https://closedcast.com/APIV1/ZapierEvents?eventType=video.created

Video

  • video.created
  • video.updated
  • video.deleted
  • video.refreshed
  • video.ready
  • video.playback.requested
  • video.upload_session.created
  • video.upload_session.failed

Categories

  • category.created
  • category.updated
  • category.deleted

Invites & Sharing

  • invite.sent
  • invite.updated
  • invite.revoked
  • share.accepted

Contacts & Offers

  • contact.created
  • contact.updated
  • contact.deleted
  • contact.captured
  • offer.submitted
Examples

Common workflows

Upload from Zapier or cloud storage

Use UploadVideoFromUrl when a prior Zap step gives you a downloadable file URL from Google Drive, Dropbox, OneDrive, Box, SharePoint, Gmail Attachments, or Google Forms.

curl.exe -X POST "https://closedcast.com/APIv1/UploadVideoFromUrl" ^
  -H "Authorization: Bearer YOUR_API_TOKEN" ^
  -H "Content-Type: application/json" ^
  -d "{\"Title\":\"Sunday Service\",\"Description\":\"Uploaded from Zapier\",\"CategoryID\":\"CATEGORY_ID\",\"FileUrl\":\"https://example.com/video.mp4\"}"
Secure Downloads

Download a video as MP4

GET

Check status and receive a signed URL

Use mode=json for API clients, Zapier, command-line tools, and applications that want to inspect download status before retrieving the file. ClosedCast authenticates the request, verifies tenant access, and asks Cloudflare to prepare the MP4 when needed.

curl.exe -i "https://closedcast.com/APIv1/Download?id=VIDEO_ID&mode=json" ^
  -H "Authorization: Bearer YOUR_API_TOKEN" ^
  -H "Accept: application/json"

Processing response

HTTP/1.1 202 Accepted
Retry-After: 10

{
  "ok": true,
  "version": "v1",
  "status": "processing",
  "download": {
    "VideoID": "VIDEO_ID",
    "Title": "Family Video",
    "Format": "video/mp4",
    "PercentComplete": 42,
    "RetryAfterSeconds": 10
  }
}

Download the file through a redirect

Omit mode=json and use a client that follows redirects. When the MP4 is ready, ClosedCast returns 302 Found with a short-lived Cloudflare URL. Cloudflare then delivers the file directly, so ClosedCast does not proxy the video bytes.

curl.exe -L "https://closedcast.com/APIv1/Download?id=VIDEO_ID" ^
  -H "Authorization: Bearer YOUR_API_TOKEN" ^
  --progress-bar ^
  -o "closedcast-video.mp4"

Ready JSON response

{
  "ok": true,
  "version": "v1",
  "status": "ready",
  "download": {
    "VideoID": "VIDEO_ID",
    "Title": "Family Video",
    "FileName": "FamilyVideo.mp4",
    "Format": "video/mp4",
    "Url": "https://customer.cloudflarestream.com/SIGNED_TOKEN/downloads/default.mp4",
    "ExpiresUtc": "2026-07-13T18:30:00Z"
  }
}

Download response flow

The same endpoint is called repeatedly. A 202 Accepted response means Cloudflare is preparing the downloadable MP4. Wait for the number of seconds in Retry-After or RetryAfterSeconds, then call the endpoint again. A ready request returns either JSON or a 302 redirect, depending on the selected mode.

GET /APIv1/Download?id=VIDEO_ID&mode=json
        |
        +-- 202 processing -- wait and retry
        |
        +-- 200 ready JSON -- download the returned Url

GET /APIv1/Download?id=VIDEO_ID
        |
        +-- 202 processing -- wait and retry
        |
        +-- 302 redirect -- Cloudflare delivers the MP4

Cloudflare Stream provides an encoded MP4 download. It is not guaranteed to be the exact original uploaded file. Do not save a 202 JSON response using an .mp4 filename.

Examples

Refresh processing status

Refresh processing status

Videos usually move from processing to ready. Use RefreshVideo or the scheduled processing refresh job to keep MongoDB synchronized with Cloudflare.

curl.exe -X POST "https://closedcast.com/APIv1/RefreshVideo" ^
  -H "Authorization: Bearer YOUR_API_TOKEN" ^
  -H "Content-Type: application/json" ^
  -d "{\"VideoID\":\"VIDEO_ID\"}"
AI Agent Summary

Machine-readable API summary

This summary is intentionally structured so AI coding agents can quickly understand how to call the ClosedCast API.

product: ClosedCast
category: Private Streaming Archive
base_url: https://closedcast.com/APIv1
authentication:
  type: Bearer Token
  header: Authorization
  example: Authorization: Bearer YOUR_API_TOKEN

core_resources:
  - Account
  - Videos
  - Downloads
  - Categories
  - Users
  - Invites
  - Contacts
  - Search
  - Events

recommended_upload_for_automation:
  endpoint: UploadVideoFromUrl
  method: POST
  reason: Works naturally with Zapier and cloud-file URLs.

video_status_flow:
  - uploading
  - processing
  - ready
  - upload_failed

download_flow:
  endpoint: Download
  method: GET
  status_mode: /Download?id=VIDEO_ID&mode=json
  redirect_mode: /Download?id=VIDEO_ID
  processing_response: HTTP 202 with Retry-After
  ready_json_response: HTTP 200 with short-lived Url
  ready_redirect_response: HTTP 302 to Cloudflare MP4

brand_principle:
  ClosedCast is built for archives, not algorithms.