# ReedTV API Programmatic access to your ReedTV account: manage videos, sync your BYOA (Bring Your Own Cloudflare Stream Account) library, and read analytics. - **Base URL:** `https://reedtv.com` - **Format:** JSON. All request bodies and responses are `application/json`. - **Stability:** This is the supported public API. Endpoints not listed here are internal and may change without notice; do not depend on them. --- ## Authentication All API requests authenticate with an **API key** in the `Authorization` header: ``` Authorization: Bearer rtv_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ``` Create and manage keys from the **Developer** page in your ReedTV portal: `https://reedtv.com/api-keys.html`. The full key is shown **once** at creation — store it securely (it cannot be retrieved later). Keys do not expire unless you set an expiry, and can be revoked at any time. > API keys are scoped (see below) and can only reach the endpoints documented > here. They cannot access billing, account, or admin functionality. ### Scopes A key is granted one or more scopes. A request to an endpoint whose required scope the key lacks returns `403`. | Scope | Grants | |-------|--------| | `videos:read` | List/read videos, storage usage, captions | | `videos:write` | Create/update/delete videos, copy to shared, bulk ops, manage captions | | `vendors:read` | List BYOA accounts and their remote (Cloudflare Stream) videos | | `vendors:write` | Connect/verify/sync/delete BYOA accounts | | `analytics:read` | Read analytics overview and per-video analytics | --- ## Conventions - **Success:** `2xx` with a JSON body. Many write endpoints return `{ "success": true, "data": ... }`. - **Error:** non-`2xx` with `{ "success": false, "error": "message" }`. - **Auth errors:** `401` (missing/invalid/expired/revoked key), `403` (missing scope, suspended account, or endpoint not available to API keys). - **Pagination:** list endpoints accept `?page=` (default 1) and `?limit=` (default 20) and return a `pagination` object. - **IDs:** videos are addressed by their `publicId` (a UUID). BYOA accounts are addressed by their numeric `accountId`. --- ## Endpoints ### Videos #### `GET /api/videos` — list videos Scope: `videos:read` Query: `page`, `limit`, `status` (`pending|processing|ready|error`), `search`, `vendor` (`shared|byoa`), `sort` (`created_at|title|status|duration_seconds`), `order` (`asc|desc`). ```bash curl -s https://reedtv.com/api/videos?limit=50 \ -H "Authorization: Bearer $REEDTV_API_KEY" ``` Response: ```json { "success": true, "data": [ { "videoId": 123, "publicId": "8f3c…", "title": "My video", "status": "ready", "errorReason": null, "duration": 612, "dimensions": { "width": 1920, "height": 1080 }, "isPublic": true, "viewCount": 42, "vendor": { "type": "byoa", "accountId": 5 }, "watchUrl": "https://reedtv.com/watch?v=8f3c…", "createdAt": "2026-06-01 12:00:00" } ], "pagination": { "page": 1, "limit": 50, "total": 1, "totalPages": 1 } } ``` #### `GET /api/videos/{publicId}` — get one video (incl. playback + embed) Scope: `videos:read`. Returns `video`, `playback` (hls/dash/iframe/thumbnail), `watchUrl`, `embedUrl`, and a ready-to-paste `embedCode` iframe. ```bash curl -s https://reedtv.com/api/videos/8f3c… \ -H "Authorization: Bearer $REEDTV_API_KEY" ``` #### `GET /api/videos/storage` — storage usage & plan Scope: `videos:read`. Returns shared-storage minutes used/included, overage, BYOA video count, plan info, and spending cap. #### `POST /api/videos` — create a video + get an upload URL Scope: `videos:write`. Creates a video record and returns a one-time upload URL. **The file itself is uploaded directly to Cloudflare Stream** at the returned `upload.url` (it does not pass through ReedTV). Use `uploadType: "tus"` for resumable uploads of large files. Body: ```json { "title": "My video", "description": "optional", "vendorAccountId": 5, "uploadType": "direct", "fileSizeBytes": 104857600 } ``` `vendorAccountId` is optional — omit (or null) to upload to ReedTV shared storage; provide a BYOA account id to upload to your own Cloudflare Stream. Response (`201`): ```json { "video": { "videoId": 124, "publicId": "…", "vendorVideoId": "…", "status": "pending" }, "upload": { "url": "https://upload.videodelivery.net/…", "type": "direct", "expiresAt": "…" }, "watchUrl": "https://reedtv.com/watch?v=…" } ``` Upload step (direct): ```bash curl -X POST "" -F file=@/path/to/video.mp4 ``` The video then processes asynchronously; poll `GET /api/videos/{publicId}` until `status` is `ready` (or `error`, with `errorReason`). #### `PUT /api/videos/{publicId}` — update metadata Scope: `videos:write`. Body may include `title`, `description`, `ogTitle`, `ogDescription`, `ogImageUrl`, `isPublic`, `embedSettings`. #### `DELETE /api/videos/{publicId}` — delete a video Scope: `videos:write`. Query `?keepRemote=true` removes it from ReedTV only and leaves the video in your BYOA Cloudflare Stream account. #### `POST /api/videos/{publicId}/copy-to-shared` — copy a BYOA video to shared storage Scope: `videos:write`. #### `POST /api/videos/bulk-copy-to-shared` — copy up to 20 BYOA videos Scope: `videos:write`. Body: `{ "publicIds": ["…", "…"] }`. #### `POST /api/videos/bulk-delete` — delete up to 50 videos Scope: `videos:write`. Body: `{ "publicIds": ["…"] }`. Query `?keepRemote=true` supported. #### Captions - `GET /api/videos/{publicId}/captions` — list captions (`videos:read`) - `POST /api/videos/{publicId}/captions` — generate (`{ "action": "generate", "language": "en" }`) or upload a VTT (`{ "language": "en", "vttContent": "WEBVTT…" }`) (`videos:write`) - `GET /api/videos/{publicId}/captions/{lang}/vtt` — download VTT (`videos:read`) - `DELETE /api/videos/{publicId}/captions/{lang}` — delete (`videos:write`) --- ### BYOA accounts (Bring Your Own Cloudflare Stream Account) #### `GET /api/vendor-accounts` — list connected accounts Scope: `vendors:read`. ```json { "accounts": [ { "accountId": 5, "accountName": "My CF", "isActive": true, "cloudflare": { "accountId": "abc123" }, "videoCount": 87 } ] } ``` #### `GET /api/vendor-accounts/{accountId}/remote-videos` — list videos in your Cloudflare Stream account Scope: `vendors:read`. Returns the videos present in your CF Stream account, flagged with whether each is already imported into ReedTV. Use this to discover what to sync. #### `POST /api/vendor-accounts/{accountId}/sync` — import remote videos into ReedTV Scope: `vendors:write`. Body: `{ "vendorVideoIds": ["uid1", "uid2"] }` to import specific videos. Each imported video gets a ReedTV `publicId` and `watchUrl`. ```bash curl -X POST https://reedtv.com/api/vendor-accounts/5/sync \ -H "Authorization: Bearer $REEDTV_API_KEY" \ -H "Content-Type: application/json" \ -d '{"vendorVideoIds":["a1b2c3d4e5f6"]}' ``` #### `POST /api/vendor-accounts/{accountId}/verify` — re-verify credentials Scope: `vendors:write`. #### `POST /api/vendor-accounts` — connect a new BYOA account Scope: `vendors:write`. Body: `{ "accountName": "…", "cfAccountId": "…", "cfApiToken": "…" }` (token needs Cloudflare Stream:Edit). Pro/BYOA plans only. #### `DELETE /api/vendor-accounts/{accountId}` — disconnect a BYOA account Scope: `vendors:write`. Removes the account from ReedTV (your Cloudflare Stream videos are not deleted). --- ### Analytics #### `GET /api/analytics/overview` — account-wide analytics Scope: `analytics:read`. #### `GET /api/analytics/videos/{publicId}` — per-video analytics Scope: `analytics:read`. Views, countries, referrers, and time series. --- ## Typical BYOA automation flow 1. `GET /api/vendor-accounts` → find your `accountId`. 2. `GET /api/vendor-accounts/{accountId}/remote-videos` → list CF Stream videos not yet in ReedTV. 3. `POST /api/vendor-accounts/{accountId}/sync` with their `vendorVideoIds` → import them. 4. `GET /api/videos?vendor=byoa&limit=100` → read back each video's `watchUrl`. 5. Paste each `watchUrl` into a post on any platform that supports rich embeds — the embed-compatible watch URL is what makes the player render. Required scopes for this flow: `vendors:read`, `vendors:write`, `videos:read`. --- ## Fair use API keys are intended for normal automation. Please keep request rates reasonable (poll processing videos no more than once every few seconds). Abusive traffic may be throttled or have keys revoked.