Reference
REST API
Full HTTP/JSON API for channels, content, scheduling, uploads, and analytics. All responses use the standard error envelope and ISO 8601 timestamps.
Base URL
All paths are relative to:
https://api.vidiyo.comAuthentication
Pass your token in the Authorization header. For automation, use a creator API key. Generate one in Studio → Account → API Keys.
Authorization: Bearer vk_live_...Scopes
API keys are scoped. Requests from a key missing a required scope receive 403 forbidden. Session-authenticated callers (browser or TV) are not scope-restricted.
| Scope | Grants access to |
|---|---|
content:read | GET /v1/creator/content/* |
content:write | Upload, update, delete content |
schedule:read | GET /v1/creator/schedule |
schedule:write | Create, move, delete schedule blocks |
channel:read | GET /v1/creator/channels/* |
channel:write | Create, update, publish channels |
analytics:read | GET /v1/creator/analytics/* |
Errors
Every non-2xx response uses this envelope:
{
"error": {
"code": "schedule.overlap",
"message": "That time slot already has a block.",
"details": { "conflictingBlockId": "01936f4e-..." },
"requestId": "req_01HJ..."
}
}| Status | When |
|---|---|
| 400 | Malformed request body or missing required parameter |
| 401 | Missing or invalid bearer token |
| 403 | Valid token but insufficient scope or wrong owner |
| 404 | Resource not found or not owned by the caller |
| 409 | Conflict — e.g. schedule overlap, duplicate key |
| 422 | Validation failure — details.issues has field-level errors |
| 429 | Rate limited — Retry-After header included |
API Keys — /v1/creator/api-keys
Create and revoke long-lived API keys for automated access. The plaintext token is returned once on creation. List and create operations require a session (browser or TV token) — API keys cannot create other keys.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /v1/creator/api-keys | Session | List all non-revoked keys (with isExpired flag) |
| POST | /v1/creator/api-keys | Session | Create a key. Token returned once — store it. |
| DELETE | /v1/creator/api-keys/:id | Session or key | Revoke a key immediately. Idempotent. |
Create a key — request body
{
"name": "My video agent", // required, 1–100 chars
"scopes": ["content:write", "schedule:write"], // required, at least one
"expiresInDays": 90 // optional; omit for non-expiring
}Create a key — response
{
"key": {
"id": "01936f4e-...",
"name": "My video agent",
"keyPrefix": "vk_live_Ab1cD2", // first 16 chars, safe to display
"scopes": ["content:write", "schedule:write"],
"expiresAt": "2026-08-01T00:00:00.000Z",
"createdAt": "2026-05-03T09:00:00.000Z",
"token": "vk_live_Ab1cD2..." // full plaintext — shown ONCE
}
}Uploads — /v1/creator/uploads
Two-step direct-to-R2 upload. Init returns a presigned URL; your client PUTs the bytes directly to R2 (no Vidiyo server in the upload path), then calls complete to trigger transcoding.
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /v1/creator/uploads/direct/init | content:write | Create content row + presigned PUT URL (15 min TTL, max 5 GB) |
| POST | /v1/creator/uploads/direct/complete | content:write | Verify bytes landed, enqueue transcoding |
| POST | /v1/creator/uploads/tus/init | content:write | Start resumable upload (TUS, up to 50 GB) |
Init request body
{
"filename": "episode-1.mp4",
"title": "Episode 1",
"contentType": "video/mp4",
"sizeBytes": 52428800,
"channelId": "01936f4e-..." // optional — attach immediately
}Init response
{
"contentItemId": "01936f4e-...",
"objectKey": "uploads/.../episode-1.mp4",
"uploadUrl": "https://r2.vidiyo.com/...?X-Amz-Signature=...",
"expiresInSeconds": 900
}Content — /v1/creator/content
Manage content items in your library. Filter by status to find ready-to-schedule videos.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /v1/creator/content | content:read | List content items (filterable by status, channel, title) |
| GET | /v1/creator/content/:id | content:read | Content detail with renditions and captions |
| PATCH | /v1/creator/content/:id | content:write | Update title, description, channel, tags |
| DELETE | /v1/creator/content/:id | content:write | Soft-delete (status → deleted) |
| POST | /v1/creator/content/:id/retry | content:write | Re-enqueue transcoding for a failed item |
List query parameters
| Param | Type | Description |
|---|---|---|
status | string | Filter: uploading | pending_transcode | transcoding | ready | failed | blocked |
channel_id | UUID | Filter by channel |
q | string | Title substring search |
sort | string | created_at | title | duration | views (default: created_at) |
direction | string | asc | desc (default: desc) |
page | int | Page number (default: 1) |
per_page | int | Items per page, max 100 (default: 20) |
Content status lifecycle
uploading → pending_transcode → transcoding → [pending_moderation →] ready
↘ failed (retryable via POST /:id/retry)Only ready items can be placed on a schedule. Poll until the status field equals ready.
Schedule — /v1/creator/schedule
Manage the EPG (electronic programme guide) for your channels. Blocks are non-overlapping; the API returns 409 with conflictingBlockId if you try to place a block in an occupied slot.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /v1/creator/schedule | schedule:read | Schedule blocks + gaps for a channel + date window |
| POST | /v1/creator/schedule | schedule:write | Create a schedule block |
| PATCH | /v1/creator/schedule/:id | schedule:write | Move, resize, or swap content of a block |
| DELETE | /v1/creator/schedule/:id | schedule:write | Remove a block. Content item is not deleted. |
| POST | /v1/creator/schedule/fill | schedule:write | Trigger async auto-fill to cover gaps with library content |
GET parameters
GET /v1/creator/schedule?channelId=UUID&from=2026-05-03T00:00:00Z&to=2026-05-04T00:00:00ZPOST body (create block)
{
"channelId": "01936f4e-...",
"contentItemId": "01936f4e-...", // must have status "ready"
"startsAt": "2026-05-03T14:00:00Z",
"kind": "content",
"durationSeconds": 1800 // optional; defaults to content's transcoded duration
}GET response
{
"channelId": "01936f4e-...",
"from": "2026-05-03T00:00:00.000Z",
"to": "2026-05-04T00:00:00.000Z",
"blocks": [
{
"id": "01936f4e-...",
"startsAt": "2026-05-03T14:00:00.000Z",
"endsAt": "2026-05-03T14:30:00.000Z",
"durationSeconds": 1800,
"kind": "content",
"content": { "id": "...", "title": "Episode 1", "status": "ready", ... }
}
],
"gaps": [
{ "from": "2026-05-03T00:00:00.000Z", "to": "2026-05-03T14:00:00.000Z" }
],
"total": 1
}Channels — /v1/creator/channels
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /v1/creator/channels | channel:read | List channels owned by the caller |
| POST | /v1/creator/channels | channel:write | Create a channel |
| PATCH | /v1/creator/channels/:id | channel:write | Update name, description, kind, category |
| POST | /v1/creator/channels/:id/publish | channel:write | Publish a draft channel |
| POST | /v1/creator/channels/:id/unpublish | channel:write | Take a channel offline |
Analytics — /v1/creator/analytics
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /v1/creator/analytics/stream | analytics:read | SSE: live KPIs (viewers, views, impressions) every 5s |
| GET | /v1/creator/analytics/summary | analytics:read | Dashboard summary: today vs last week, revenue, content count |
Rate limits
Limits apply per user (authenticated) or per IP (anonymous). All limits use a sliding window. Responses include Retry-After when limited.
| Scope | Path | Window | Limit |
|---|---|---|---|
uploads | /v1/creator/uploads/* | 1 min | 60 |
search | /v1/search | 1 min | 60 |
api_key_create | /v1/creator/api-keys | 60 min | 20 |
oauth_exchange | /v1/auth/oauth/* | 60 min | 10 |
beacons | /v1/beacons/* | 1 min | 600 |
Need the full spec?
The authoritative machine-readable spec is the OpenAPI 3.1 document. Browse it interactively or download it to generate client SDKs.