# Subscribr Customer API Reference Generated from `openapi/subscribr-v1.json`. Do not infer undocumented routes. - Base URL: `https://subscribr.ai` - Authentication: `Authorization: Bearer ` - Contract: [OpenAPI 3.1.2](https://subscribr.ai/openapi.json) - Subscribr Video public operations use `/api/v1/video/...` as capability slices ship. YouTube research remains available through the Intel video operations. ## Channels ### `GET /api/v1/channels` **Operation ID:** `listChannels` **Purpose:** List Channels. **Abilities:** `channels:read` **Parameters** - `search` — query, optional - `per_page` — query, optional - `page` — query, optional **Response `200` example** ```json { "success": true, "data": [ { "id": 123, "yt_handle": "mkbhd", "details": { "title": "Marques Brownlee", "custom_url": "mkbhd", "channel_id": "UCBJycsmduvYEL83R_U4JriQ", "subscriber_count": 19000000, "video_count": 1650, "view_count": 4200000000, "description": "Channel description", "country": "US", "default_language": "en", "thumbnails": { "default": { "url": "https://i.ytimg.com/..." } } }, "scripts_count": 42 } ], "pagination": { "current_page": 1, "per_page": 20, "total": 1, "last_page": 1 } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `GET /api/v1/channels/{channel}` **Operation ID:** `getChannel` **Purpose:** Get Channel. **Abilities:** `channels:read` **Parameters** - `channel` — path, required **Response `200` example** ```json { "success": true, "data": { "id": 123, "yt_handle": "mkbhd", "details": { "title": "Marques Brownlee", "custom_url": "mkbhd", "channel_id": "UCBJycsmduvYEL83R_U4JriQ", "subscriber_count": 19000000, "video_count": 1650, "view_count": 4200000000, "description": "Channel description", "default_language": "en", "country": "US", "thumbnails": { "default": { "url": "https://i.ytimg.com/..." } } }, "settings": { "language": "English", "audience": "Tech enthusiasts" }, "voice": { "id": 77, "name": "Default Voice", "instructions": "Voice instructions", "voice": "neutral" }, "scripts_count": 42, "scripts_idea_count": 4, "scripts_active_count": 38 } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `GET /api/v1/channels/{channel}/competitors` **Operation ID:** `listChannelCompetitors` **Purpose:** List Channel Competitors. **Abilities:** `channels:read` **Parameters** - `channel` — path, required **Response `200` example** ```json { "success": true, "data": [] } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `POST /api/v1/channels/{channel}/competitors` **Operation ID:** `addChannelCompetitor` **Purpose:** Add Channel Competitor. **Abilities:** `scripts:write` **Write safety:** idempotency `unsupported`; concurrency `unsupported`; retry `never`. **Parameters** - `channel` — path, required **Request example** ```json { "identifier": "https://www.youtube.com/@competitor" } ``` **Response `201` example** ```json { "success": true, "data": { "channel_id": 1, "competitor": { "channel_id": "UC123", "handle": "competitor", "title": "Competitor" } } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `DELETE /api/v1/channels/{channel}/competitors/{competitor}` **Operation ID:** `deleteChannelCompetitor` **Purpose:** Delete Channel Competitor. **Abilities:** `scripts:write` **Write safety:** idempotency `unsupported`; concurrency `unsupported`; retry `never`. **Parameters** - `channel` — path, required - `competitor` — path, required **Response `200` example** ```json { "success": true, "message": "Competitor removed." } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ## Ideas ### `GET /api/v1/channels/{channel}/ideas` **Operation ID:** `listChannelIdeas` **Purpose:** List Channel Ideas. **Abilities:** `scripts:read` **Parameters** - `channel` — path, required - `status` — query, optional - `source_type` — query, optional - `search` — query, optional - `per_page` — query, optional - `page` — query, optional **Response `200` example** ```json { "success": true, "data": [ { "id": 456, "channel_id": 123, "title": "Why Apple's AI Changes Everything", "topic": "Analysis of Apple Intelligence", "angle": "Reveal the hidden implication...", "suggested_length": 1200, "suggested_template_id": 22, "status": "new", "script_id": null, "source_type": "user_added", "thumbnail_concept": "Split-screen before/after with bold headline", "outlier_score": null, "notes": null } ], "pagination": { "current_page": 1, "per_page": 20, "total": 1, "last_page": 1 } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `POST /api/v1/channels/{channel}/ideas` **Operation ID:** `createChannelIdea` **Purpose:** Create Channel Idea. **Abilities:** `scripts:write` **Write safety:** idempotency `unsupported`; concurrency `unsupported`; retry `never`. **Parameters** - `channel` — path, required **Request example** ```json { "title": "Why Apple's AI Changes Everything", "topic": "Analysis of Apple Intelligence", "angle": "Reveal the hidden implication that most reviews miss.", "suggested_length": 1200, "suggested_template_id": 22, "thumbnail_concept": "Split-screen before/after with bold headline", "notes": "Focus on practical consequences." } ``` **Response `201` example** ```json { "success": true, "data": { "id": 456, "channel_id": 123, "title": "Why Apple's AI Changes Everything", "topic": "Analysis of Apple Intelligence", "angle": "Reveal the hidden implication that most reviews miss.", "suggested_length": 1200, "suggested_template_id": 22, "status": "new", "script_id": null, "source_type": "user_added", "thumbnail_concept": "Split-screen before/after with bold headline", "outlier_score": null, "notes": null } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `POST /api/v1/channels/{channel}/ideas/generate` **Operation ID:** `generateChannelIdeas` **Purpose:** Generate Channel Ideas. **Abilities:** `scripts:write` **Write safety:** idempotency `unsupported`; concurrency `unsupported`; retry `never`. **Parameters** - `channel` — path, required **Request example** ```json { "count": 10 } ``` **Response `202` example** ```json { "success": true, "message": "Idea generation started.", "data": { "channel_id": 123, "count": 10 } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `POST /api/v1/channels/{channel}/ideas/generate-from-channel` **Operation ID:** `generateIdeasFromChannel` **Purpose:** Generate Ideas From Channel. **Abilities:** `scripts:write` **Write safety:** idempotency `unsupported`; concurrency `unsupported`; retry `never`. **Parameters** - `channel` — path, required **Request example** ```json { "channel_handle": "@mkbhd", "count": 10 } ``` **Response `202` example** ```json { "success": true, "message": "Idea generation from channel started.", "data": { "channel_id": 123, "source_channel_title": "Marques Brownlee", "count": 10 } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `POST /api/v1/channels/{channel}/ideas/generate-from-video` **Operation ID:** `generateIdeasFromVideo` **Purpose:** Generate Ideas From Video. **Abilities:** `scripts:write` **Write safety:** idempotency `unsupported`; concurrency `unsupported`; retry `never`. **Parameters** - `channel` — path, required **Request example** ```json { "video_url": "https://youtube.com/watch?v=dQw4w9WgXcQ", "count": 10 } ``` **Response `202` example** ```json { "success": true, "message": "Idea generation from video started.", "data": { "channel_id": 123, "count": 10 } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `GET /api/v1/ideas/{idea}` **Operation ID:** `getIdea` **Purpose:** Get Idea. **Abilities:** `scripts:read` **Parameters** - `idea` — path, required **Response `200` example** ```json { "success": true, "data": { "id": 456, "channel_id": 123, "title": "Why Apple's AI Changes Everything", "topic": "Analysis of Apple Intelligence", "angle": "Reveal the hidden implication...", "suggested_length": 1200, "suggested_template_id": 22, "status": "new", "script_id": null, "source_type": "user_added", "thumbnail_concept": "Split-screen before/after", "outlier_score": null, "notes": null } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `POST /api/v1/ideas/{idea}/change-topic` **Operation ID:** `changeIdeaTopic` **Purpose:** Change Idea Topic. **Abilities:** `scripts:write` **Write safety:** idempotency `unsupported`; concurrency `unsupported`; retry `never`. **Parameters** - `idea` — path, required **Request example** ```json { "topic": "Instead of productivity apps, apply this to morning routines" } ``` **Response `202` example** ```json { "success": true, "message": "Topic change started.", "data": { "idea_id": 456 } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `POST /api/v1/ideas/{idea}/write` **Operation ID:** `writeIdea` **Purpose:** Write Idea. **Abilities:** `scripts:write` **Write safety:** idempotency `unsupported`; concurrency `unsupported`; retry `never`. **Parameters** - `idea` — path, required **Response `201` example** ```json { "success": true, "data": { "script_id": 789, "script_number": 12, "thread_id": 456, "canvas_url": "https://subscribr.ai/chat/my-channel-thread/canvas/789" } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ## Intel ### `GET /api/v1/intel/bookmarks` **Operation ID:** `listIntelBookmarks` **Purpose:** List Intel Bookmarks. **Abilities:** `intel:read` **Parameters** - `page` — query, optional - `bookmark` — query, required **Response `200` example** ```json { "success": true, "data": [], "pagination": { "current_page": 1, "per_page": 50, "total": 0, "last_page": 1 } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `POST /api/v1/intel/bookmarks` **Operation ID:** `createIntelBookmark` **Purpose:** Create Intel Bookmark. **Abilities:** `intel:write` **Write safety:** idempotency `unsupported`; concurrency `unsupported`; retry `never`. **Parameters** - `page` — query, optional - `bookmark` — query, required **Request example** ```json { "type": "channel", "external_id": "UCBJycsmduvYEL83R_U4JriQ", "title": "Competitor: MKBHD", "url": "https://youtube.com/@mkbhd", "notes": "Strong format", "tags": [ "competitor" ] } ``` **Response `201` example** ```json { "success": true, "data": { "id": 1, "type": "channel", "external_id": "UCBJycsmduvYEL83R_U4JriQ", "title": "Competitor: MKBHD", "url": "https://youtube.com/@mkbhd", "notes": "Strong format", "tags": [ "competitor" ] } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `DELETE /api/v1/intel/bookmarks/{bookmark}` **Operation ID:** `deleteIntelBookmark` **Purpose:** Delete Intel Bookmark. **Abilities:** `intel:write` **Write safety:** idempotency `unsupported`; concurrency `unsupported`; retry `never`. **Parameters** - `bookmark` — path, required **Response `200` example** ```json { "success": true, "message": "Bookmark deleted successfully" } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `POST /api/v1/intel/channels/lookup` **Operation ID:** `lookupIntelChannel` **Purpose:** Lookup Intel Channel. **Abilities:** `intel:read` **Write safety:** idempotency `unsupported`; concurrency `unsupported`; retry `never`. **Request example** ```json { "identifiers": [ "@mkbhd", "UCBJycsmduvYEL83R_U4JriQ" ] } ``` **Response `200` example** ```json { "success": true, "data": { "channels": [ { "channel_id": "UCBJycsmduvYEL83R_U4JriQ", "handle": "mkbhd", "title": "Marques Brownlee", "description": "Channel description (truncated to 500 chars)", "thumbnails": { "default": { "url": "https://i.ytimg.com/..." } }, "subscriber_count": 19000000, "video_count": 1650, "view_count": 4200000000, "published_at": "2008-01-20T00:00:00Z", "country": "US" } ], "errors": [] } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `POST /api/v1/intel/channels/search` **Operation ID:** `searchIntelChannels` **Purpose:** Search Intel Channels. **Abilities:** `intel:read` **Write safety:** idempotency `unsupported`; concurrency `unsupported`; retry `never`. **Request example** ```json { "query": "tech reviews", "limit": 10 } ``` **Response `200` example** ```json { "success": true, "data": { "channels": [ { "channel_id": "UCBJycsmduvYEL83R_U4JriQ", "handle": "mkbhd", "title": "Marques Brownlee", "description": "Channel description (truncated to 500 chars)", "thumbnails": { "default": { "url": "https://i.ytimg.com/..." } }, "published_at": "2008-01-20T00:00:00Z", "subscriber_count": 19000000, "video_count": 1650, "view_count": 4200000000, "country": "US" } ], "query": "tech reviews", "total_results": 1, "message": "Channels found matching your criteria." } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `POST /api/v1/intel/videos/lookup` **Operation ID:** `lookupIntelVideo` **Purpose:** Lookup Intel Video. **Abilities:** `intel:read` **Write safety:** idempotency `unsupported`; concurrency `unsupported`; retry `never`. **Request example** ```json { "identifiers": [ "dQw4w9WgXcQ", "https://youtube.com/watch?v=abc123" ] } ``` **Response `200` example** ```json { "success": true, "data": { "videos": [ { "video_id": "dQw4w9WgXcQ", "channel": { "channel_id": "UCuAXFkgsw1L7xaCfnd5JJOw", "handle": "RickAstleyVEVO", "title": "Rick Astley" }, "title": "Video Title", "description": "Video description", "published_at": "2009-10-25T06:57:33Z", "thumbnail_url": "https://i.ytimg.com/...", "duration": "PT3M33S", "view_count": 1000000, "like_count": 50000, "comment_count": 10000, "outlier_score": 1.25, "format": "Music", "topic": "Pop", "angle": "Nostalgia", "goals": "Entertainment" } ], "errors": [] } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `POST /api/v1/intel/videos/search` **Operation ID:** `searchIntelVideos` **Purpose:** Search Intel Videos. **Abilities:** `intel:read` **Write safety:** idempotency `unsupported`; concurrency `unsupported`; retry `never`. **Request example** ```json { "query": "iPhone 15 review", "limit": 20 } ``` **Response `200` example** ```json { "success": true, "data": { "videos": [ { "video_id": "abc123", "channel": { "channel_id": "UCBJycsmduvYEL83R_U4JriQ", "handle": "mkbhd", "title": "Marques Brownlee" }, "title": "iPhone 15 Review", "description": "Description (truncated to 300 chars)...", "published_at": "2026-01-01T00:00:00Z", "thumbnail_url": "https://i.ytimg.com/...", "view_count": 500000, "like_count": 15000, "comment_count": 1200, "duration": "PT12M", "format": "Review", "topic": "Smartphones", "angle": "Hands-on", "goals": "Inform", "outlier_score": 1.12 } ], "query": "iPhone 15 review", "total_results": 1, "message": "Videos found matching your criteria." } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ## Operations ### `GET /api/v1/operations/{operation}` **Operation ID:** `getOperation` **Purpose:** Get an asynchronous operation. **Abilities:** `operations:read` **Parameters** - `operation` — path, required **Response `200` example** ```json { "data": { "id": "6b33d5a6-72c8-4e1e-9bc4-8024f38be3fb", "type": "generate_ideas", "status": "running", "progress": 10, "result": null, "warnings": [], "error": null, "retry": { "supported": false, "action": null, "after": null }, "timestamps": { "created_at": "2026-07-29T00:00:00+00:00", "started_at": "2026-07-29T00:00:01+00:00", "finished_at": null, "expires_at": "2026-08-05T00:00:00+00:00" }, "domain_resource": null } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ## Projects ### `GET /api/v1/projects` **Operation ID:** `listProjects` **Purpose:** List Projects. **Abilities:** `projects:read` **Parameters** - `Cursor` (shared header parameter) - `channel_ids[]` — query, optional - `search` — query, optional - `include_archived` — query, optional - `limit` — query, optional - `expand` — query, optional **Response `200` example** ```json { "data": [], "meta": { "next_cursor": null } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `POST /api/v1/projects` **Operation ID:** `createProject` **Purpose:** Create Project. **Abilities:** `projects:write` **Write safety:** idempotency `required`; concurrency `optional`; retry `same-key`. **Parameters** - `IdempotencyKey` (shared header parameter) - `IfMatch` (shared header parameter) **Request example** ```json { "channel_id": 1, "source": "idea", "title": "New idea", "stage": "new" } ``` **Response `201` example** ```json { "data": { "id": "project:v1:idea:1", "source": "idea", "title": "New idea", "revision": "revision" }, "meta": { "idempotent_replay": false } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `GET /api/v1/projects/{project}` **Operation ID:** `getProject` **Purpose:** Get Project. **Abilities:** `projects:read` **Parameters** - `project` — path, required - `expand` — query, optional **Response `200` example** ```json { "data": { "id": "project:v1:idea:1", "source": "idea", "title": "Idea", "revision": "revision" }, "meta": { "idempotent_replay": false } } ``` **Errors:** `400`, `401`, `403`, `404`, `409`, `422`, `429`, `500` ### `PATCH /api/v1/projects/{project}` **Operation ID:** `updateProject` **Purpose:** Update Project. **Abilities:** `projects:write` **Write safety:** idempotency `required`; concurrency `required`; retry `same-key`. **Parameters** - `project` — path, required - `IdempotencyKey` (shared header parameter) - `IfMatch` (shared header parameter) **Request example** ```json { "title": "Updated title" } ``` **Response `200` example** ```json { "data": { "id": "project:v1:idea:1", "source": "idea", "title": "Updated title", "revision": "revision-2" }, "meta": { "idempotent_replay": false } } ``` **Errors:** `400`, `401`, `403`, `404`, `409`, `422`, `429`, `500` ### `POST /api/v1/projects/{project}/move` **Operation ID:** `moveProject` **Purpose:** Move Project. **Abilities:** `projects:write` **Write safety:** idempotency `required`; concurrency `required`; retry `same-key`. **Parameters** - `project` — path, required - `IdempotencyKey` (shared header parameter) - `IfMatch` (shared header parameter) **Request example** ```json { "stage": "considering" } ``` **Response `200` example** ```json { "data": { "id": "project:v1:idea:1", "source": "idea", "title": "Idea", "revision": "revision-2" }, "meta": { "idempotent_replay": false } } ``` **Errors:** `400`, `401`, `403`, `404`, `409`, `422`, `429`, `500` ### `POST /api/v1/projects/{project}/promote` **Operation ID:** `promoteProject` **Purpose:** Promote idea Project. **Abilities:** `projects:write` **Write safety:** idempotency `required`; concurrency `required`; retry `same-key`. **Parameters** - `project` — path, required - `IdempotencyKey` (shared header parameter) - `IfMatch` (shared header parameter) **Request example** ```json { "stage": "scripting" } ``` **Response `200` example** ```json { "data": { "id": "project:v1:script:1", "source": "script", "title": "Idea", "revision": "revision-2" }, "meta": { "idempotent_replay": false } } ``` **Errors:** `400`, `401`, `403`, `404`, `409`, `422`, `429`, `500` ### `POST /api/v1/projects/{project}/archive` **Operation ID:** `archiveProject` **Purpose:** Archive Project. **Abilities:** `projects:write` **Write safety:** idempotency `required`; concurrency `required`; retry `same-key`. **Parameters** - `project` — path, required - `IdempotencyKey` (shared header parameter) - `IfMatch` (shared header parameter) **Response `200` example** ```json { "data": { "id": "project:v1:idea:1", "source": "idea", "title": "Idea", "revision": "revision-2" }, "meta": { "idempotent_replay": false } } ``` **Errors:** `400`, `401`, `403`, `404`, `409`, `422`, `429`, `500` ### `POST /api/v1/projects/{project}/restore` **Operation ID:** `restoreProject` **Purpose:** Restore Project. **Abilities:** `projects:write` **Write safety:** idempotency `required`; concurrency `required`; retry `same-key`. **Parameters** - `project` — path, required - `IdempotencyKey` (shared header parameter) - `IfMatch` (shared header parameter) **Response `200` example** ```json { "data": { "id": "project:v1:idea:1", "source": "idea", "title": "Idea", "revision": "revision-2" }, "meta": { "idempotent_replay": false } } ``` **Errors:** `400`, `401`, `403`, `404`, `409`, `422`, `429`, `500` ### `GET /api/v1/projects/{project}/comments` **Operation ID:** `listProjectComments` **Purpose:** List Project comments. **Abilities:** `projects:read` **Parameters** - `project` — path, required **Response `200` example** ```json { "data": [], "meta": { "truncated": false } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `POST /api/v1/projects/{project}/comments` **Operation ID:** `createProjectComment` **Purpose:** Create Project comment. **Abilities:** `projects:write` **Write safety:** idempotency `required`; concurrency `optional`; retry `same-key`. **Parameters** - `project` — path, required - `IdempotencyKey` (shared header parameter) - `IfMatch` (shared header parameter) **Request example** ```json { "body": "Ready for review.", "mentioned_user_ids": [] } ``` **Response `201` example** ```json { "data": { "id": 1, "body": "Ready for review.", "author": { "id": 1, "name": "Creator" }, "mentioned_user_ids": [], "edited_at": null, "created_at": "2026-07-22T12:00:00+00:00" }, "meta": { "no_op": false } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `GET /api/v1/projects/{project}/activity` **Operation ID:** `listProjectActivity` **Purpose:** List Project activity. **Abilities:** `projects:read` **Parameters** - `project` — path, required **Response `200` example** ```json { "data": [], "meta": { "truncated": false } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `GET /api/v1/projects/{project}/attachments` **Operation ID:** `listProjectAttachments` **Purpose:** List Project attachment metadata. **Abilities:** `projects:read` **Parameters** - `project` — path, required **Response `200` example** ```json { "data": [], "meta": { "truncated": false } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `GET /api/v1/tasks` **Operation ID:** `listProjectTasks` **Purpose:** List assigned Project tasks. **Abilities:** `projects:read` **Parameters** - `Cursor` (shared header parameter) - `limit` — query, optional - `overdue` — query, optional **Response `200` example** ```json { "data": [], "meta": { "next_cursor": null } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `GET /api/v1/project-notifications` **Operation ID:** `listProjectNotifications` **Purpose:** List Project notifications. **Abilities:** `notifications:read` **Parameters** - `Cursor` (shared header parameter) - `limit` — query, optional - `unread` — query, optional **Response `200` example** ```json { "data": [], "meta": { "next_cursor": null } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `POST /api/v1/project-notifications/{notification}/read` **Operation ID:** `readProjectNotification` **Purpose:** Mark one Project notification read. **Abilities:** `notifications:write` **Write safety:** idempotency `required`; concurrency `optional`; retry `same-key`. **Parameters** - `notification` — path, required - `IdempotencyKey` (shared header parameter) **Response `200` example** ```json { "data": { "id": "00000000-0000-4000-8000-000000000001", "type": "kanban_script_status_changed", "project_id": "project:v1:script:1", "target_available": true, "message": "Moved project", "actor": null, "read_at": "2026-07-22T12:00:00+00:00", "created_at": "2026-07-22T11:00:00+00:00" } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `POST /api/v1/project-notifications/read-all` **Operation ID:** `readAllProjectNotifications` **Purpose:** Mark all Project notifications read. **Abilities:** `notifications:write` **Write safety:** idempotency `required`; concurrency `optional`; retry `same-key`. **Parameters** - `IdempotencyKey` (shared header parameter) **Response `200` example** ```json { "data": { "marked_read": 2 } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `GET /api/v1/projects/{project}/production` **Operation ID:** `getProjectProduction` **Purpose:** Get Project production metadata. **Abilities:** `projects:read` **Parameters** - `project` — path, required **Response `200` example** ```json { "data": { "project_id": "project:v1:script:1", "stage": "upload", "thumbnail": { "text": null, "winner_selected": false, "review_status": null, "review_notes": null, "reviewed_at": null }, "upload": { "description": null, "tags": [], "visibility": "public", "made_for_kids": false, "status": null, "publish_at": null, "all_required_checked": true }, "checklist": [], "checklist_total": 0, "checklist_truncated": false }, "meta": { "revision": "project-r1-example", "idempotent_replay": false } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `PATCH /api/v1/projects/{project}/production` **Operation ID:** `updateProjectProduction` **Purpose:** Update Project production metadata. **Abilities:** `projects:write` **Write safety:** idempotency `required`; concurrency `required`; retry `same-key`. **Parameters** - `project` — path, required - `IdempotencyKey` (shared header parameter) - `IfMatch` (shared header parameter) **Request example** ```json { "description": "Ready to upload.", "tags": [ "tutorial" ], "visibility": "unlisted" } ``` **Response `200` example** ```json { "data": { "project_id": "project:v1:script:1", "stage": "upload", "thumbnail": { "text": null, "winner_selected": false, "review_status": null, "review_notes": null, "reviewed_at": null }, "upload": { "description": "Ready to upload.", "tags": [ "tutorial" ], "visibility": "unlisted", "made_for_kids": false, "status": null, "publish_at": null, "all_required_checked": true }, "checklist": [], "checklist_total": 0, "checklist_truncated": false }, "meta": { "revision": "project-r1-example", "idempotent_replay": false } } ``` **Errors:** `400`, `401`, `403`, `404`, `409`, `422`, `429`, `500` ## Scripts ### `GET /api/v1/channels/{channel}/scripts` **Operation ID:** `listChannelScripts` **Purpose:** List Channel Scripts. **Abilities:** `scripts:read` **Parameters** - `channel` — path, required - `status` — query, optional - `format` — query, optional - `search` — query, optional - `per_page` — query, optional - `page` — query, optional **Response `200` example** ```json { "success": true, "data": [ { "id": 789, "channel_id": 123, "script_number": 12, "title": "Why Apple's AI Changes Everything", "topic": "Break down the key changes...", "angle": "Explain the hidden implication most reviews miss", "length": 1200, "status": "active", "format": "Tutorial", "language": "English", "voice": "neutral", "template_id": 22, "production_status": "scripting", "thread_id": 456, "canvas_url": "https://subscribr.ai/chat/my-channel-thread/canvas/789", "has_outline": true, "has_script": false } ], "pagination": { "current_page": 1, "per_page": 20, "total": 1, "last_page": 1 } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `POST /api/v1/channels/{channel}/scripts` **Operation ID:** `createChannelScript` **Purpose:** Create Channel Script. **Abilities:** `scripts:write` **Write safety:** idempotency `unsupported`; concurrency `unsupported`; retry `never`. **Parameters** - `channel` — path, required **Request example** ```json { "title": "Why Apple's AI Changes Everything", "topic": "Break down the key changes in Apple Intelligence and what they mean.", "length": 1200, "angle": "Explain the hidden implication most reviews miss", "voice_id": 55, "voice": "neutral", "language": "English", "template_id": 22, "research_urls": [ "https://example.com/source-1" ], "research_texts": [ "Key bullet points" ], "prompt": "Custom starting prompt" } ``` **Response `201` example** ```json { "success": true, "data": { "script_id": 789, "script_number": 12, "thread_id": 456, "status": "active", "canvas_url": "https://subscribr.ai/chat/my-channel-thread/canvas/789" } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `GET /api/v1/scripts/{script}` **Operation ID:** `getScript` **Purpose:** Get Script. **Abilities:** `scripts:read` **Parameters** - `script` — path, required **Response `200` example** ```json { "success": true, "data": { "id": 789, "channel_id": 123, "script_number": 12, "title": "Why Apple's AI Changes Everything", "topic": "Break down the key changes...", "angle": "Explain the hidden implication most reviews miss", "length": 1200, "format": "Tutorial", "language": "English", "voice": "neutral", "template_id": 22, "status": "active", "production_status": "scripting", "thread_id": 456, "canvas_url": "https://subscribr.ai/chat/my-channel-thread/canvas/789", "has_outline": true, "has_script": false, "notes": "Notes for collaborators", "hook": "Open with a surprising fact", "thumbnail": "Apple AI Shock" } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `POST /api/v1/scripts/{script}/agent/generate` **Operation ID:** `startScriptAgentRun` **Purpose:** Start Script Agent Run. **Abilities:** `scripts:write` **Write safety:** idempotency `unsupported`; concurrency `unsupported`; retry `never`. **Parameters** - `script` — path, required **Request example** ```json { "model": "minimax_m27", "research": "deep_research", "visual_cues": "on" } ``` **Response `202` example** ```json { "run_id": 42, "status": "queued", "research": "auto", "visual_cues": "off", "model": "kimi_k26", "resolved_model": "kimi-k2.6", "poll_url": "https://subscribr.ai/api/v1/scripts/789/agent/runs/42", "cancel_url": "https://subscribr.ai/api/v1/scripts/789/agent/runs/42/cancel", "message": "Script agent run queued. Poll the poll_url for status updates." } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `GET /api/v1/scripts/{script}/agent/runs/{run}` **Operation ID:** `getScriptAgentRun` **Purpose:** Get Script Agent Run. **Abilities:** `scripts:read` **Parameters** - `script` — path, required - `run` — path, required **Response `200` example** ```json { "success": true, "data": { "run_id": 42, "status": "completed", "current_step": null, "current_step_label": null, "elapsed_seconds": 112, "executor": "claude_sdk", "auth_path": "byok_anthropic", "script_url": "https://subscribr.ai/api/v1/scripts/789", "usage": { "prompt_tokens": 8420, "completion_tokens": 1103, "reasoning_tokens": null, "total_tokens": 9523 } } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `POST /api/v1/scripts/{script}/agent/runs/{run}/cancel` **Operation ID:** `cancelScriptAgentRun` **Purpose:** Cancel Script Agent Run. **Abilities:** `scripts:write` **Write safety:** idempotency `unsupported`; concurrency `unsupported`; retry `never`. **Parameters** - `script` — path, required - `run` — path, required **Response `200` example** ```json { "cancelled": true, "run_id": 42, "status": "cancelled", "refunded": true, "message": "Run cancelled. Credits were refunded." } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `GET /api/v1/scripts/{script}/content` **Operation ID:** `getScriptContent` **Purpose:** Get Script Content. **Abilities:** `scripts:read` **Parameters** - `script` — path, required **Response `200` example** ```json { "success": true, "data": { "script_id": 789, "outline": "# Outline\\n...", "script": "# Script\\n...", "outline_version": 3, "content_version": 7 } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `GET /api/v1/scripts/{script}/export` **Operation ID:** `exportScript` **Purpose:** Export Script. **Abilities:** `scripts:read` **Parameters** - `script` — path, required - `format` — query, required - `include_headings` — query, optional **Response `200` example** ```json { "success": true, "data": { "script_id": 789, "title": "Why Apple's AI Changes Everything", "format": "markdown", "content": "# Script\\n...", "include_headings": true } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `GET /api/v1/scripts/{script}/generate/poll` **Operation ID:** `pollScriptGeneration` **Purpose:** Poll Script Generation. **Abilities:** `scripts:read` **Parameters** - `script` — path, required - `run_id` — query, required **Response `200` example** ```json { "success": true, "data": { "run_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "status": "completed", "content_type": "script", "outline": "# Outline\n\n## Section 1\n...", "script": "# Script\n\nOpening hook...\n" } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `POST /api/v1/scripts/{script}/outline/generate` **Operation ID:** `generateScriptOutline` **Purpose:** Generate Script Outline. **Abilities:** `scripts:write` **Write safety:** idempotency `unsupported`; concurrency `unsupported`; retry `never`. **Parameters** - `script` — path, required **Response `202` example** ```json { "success": true, "data": { "run_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "status": "queued" } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `POST /api/v1/scripts/{script}/script/generate` **Operation ID:** `generateScript` **Purpose:** Generate Script. **Abilities:** `scripts:write` **Write safety:** idempotency `unsupported`; concurrency `unsupported`; retry `never`. **Parameters** - `script` — path, required **Response `202` example** ```json { "success": true, "data": { "run_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "status": "queued" } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `POST /api/v1/scripts/{script}/script/humanize` **Operation ID:** `humanizeScript` **Purpose:** Humanize Script. **Abilities:** `scripts:write` **Write safety:** idempotency `unsupported`; concurrency `unsupported`; retry `never`. **Parameters** - `script` — path, required **Response `202` example** ```json { "success": true, "data": { "run_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "status": "queued" } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ## Team ### `GET /api/v1/team` **Operation ID:** `getTeam` **Purpose:** Get Team. **Abilities:** authenticated credential **Response `200` example** ```json { "team": { "id": 456, "name": "My Content Team", "user_role": "admin", "owner": { "id": 123, "name": "John Doe" }, "subscription": { "plan": "Creator", "status": "active", "trial_ends_at": null, "is_paused": false } } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `GET /api/v1/team/credits` **Operation ID:** `getTeamCredits` **Purpose:** Get Team Credits. **Abilities:** authenticated credential **Response `200` example** ```json { "credits": { "current_credits": 850, "plan_credits": 1000, "credits_used_this_period": 150, "credits_remaining": 850, "credits_expire_at": "2026-02-28T00:00:00Z", "next_credit_refresh": "2026-03-01T00:00:00Z" } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `GET /api/v1/team/tokens` **Operation ID:** `listApiTokens` **Purpose:** List Api Tokens. **Abilities:** `tokens:manage` **Response `200` example** ```json { "tokens": [ { "id": 123, "name": "Zapier Integration", "abilities": [ "intel:read", "scripts:read" ], "last_used_at": "2026-02-01T18:22:00Z" } ] } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `POST /api/v1/team/tokens` **Operation ID:** `createApiToken` **Purpose:** Create Api Token. **Abilities:** `tokens:manage` **Write safety:** idempotency `unsupported`; concurrency `unsupported`; retry `never`. **Request example** ```json { "name": "Automation Token", "abilities": [ "intel:read", "scripts:read", "channels:read" ] } ``` **Response `201` example** ```json { "token": { "id": 456, "name": "Automation Token", "abilities": [ "intel:read", "scripts:read", "channels:read" ], "token": "plain-text-token-value" } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `DELETE /api/v1/team/tokens/{token}` **Operation ID:** `deleteApiToken` **Purpose:** Delete Api Token. **Abilities:** `tokens:manage` **Write safety:** idempotency `unsupported`; concurrency `unsupported`; retry `never`. **Parameters** - `token` — path, required **Response `200` example** ```json { "message": "Token deleted successfully" } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ## Templates ### `GET /api/v1/channels/{channel}/templates` **Operation ID:** `listChannelTemplates` **Purpose:** List built-in and custom Channel templates. **Abilities:** `templates:read` **Parameters** - `channel` — path, required - `include_archived` — query, optional **Response `200` example** ```json { "data": [], "meta": { "default_template_id": null, "system_count": 20, "custom_count": 0, "custom_truncated": false } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `POST /api/v1/channels/{channel}/templates` **Operation ID:** `createTemplate` **Purpose:** Create a custom Channel template. **Abilities:** `templates:write` **Write safety:** idempotency `required`; concurrency `unsupported`; retry `same-key`. **Parameters** - `channel` — path, required - `IdempotencyKey` (shared header parameter) **Request example** ```json { "name": "My explainer", "description": "A concise teaching format.", "prompt": "Write a clear, structured explainer with a compelling opening, concrete examples, and a concise conclusion for the target audience." } ``` **Response `201` example** ```json { "data": { "id": 22, "kind": "custom", "key": null, "name": "My explainer", "slug": "my-explainer", "category": "custom", "description": "A concise teaching format.", "prompt": "Write a clear structured explainer with a compelling opening and concrete examples for the intended audience.", "is_default": false, "archived": false, "mutable": true, "revision": "template-r1-example", "created_at": "2026-07-22T12:00:00Z", "updated_at": "2026-07-22T12:00:00Z" }, "meta": { "idempotent_replay": false } } ``` **Errors:** `400`, `401`, `403`, `404`, `409`, `422`, `429`, `500` ### `GET /api/v1/channels/{channel}/templates/{template}` **Operation ID:** `getTemplate` **Purpose:** Get a custom Channel template. **Abilities:** `templates:read` **Parameters** - `channel` — path, required - `template` — path, required **Response `200` example** ```json { "data": { "id": 22, "kind": "custom", "key": null, "name": "My explainer", "slug": "my-explainer", "category": "custom", "description": null, "prompt": "Write a clear structured explainer with a compelling opening and concrete examples for the intended audience.", "is_default": false, "archived": false, "mutable": true, "revision": "template-r1-example", "created_at": "2026-07-22T12:00:00Z", "updated_at": "2026-07-22T12:00:00Z" }, "meta": { "idempotent_replay": false } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `PATCH /api/v1/channels/{channel}/templates/{template}` **Operation ID:** `updateTemplate` **Purpose:** Update a custom Channel template. **Abilities:** `templates:write` **Write safety:** idempotency `required`; concurrency `required`; retry `same-key`. **Parameters** - `channel` — path, required - `template` — path, required - `IdempotencyKey` (shared header parameter) - `IfMatch` (shared header parameter) **Request example** ```json { "name": "My revised explainer" } ``` **Response `200` example** ```json { "data": { "id": 22, "kind": "custom", "key": null, "name": "My revised explainer", "slug": "my-revised-explainer", "category": "custom", "description": null, "prompt": "Write a clear structured explainer with a compelling opening and concrete examples for the intended audience.", "is_default": false, "archived": false, "mutable": true, "revision": "template-r1-updated", "created_at": "2026-07-22T12:00:00Z", "updated_at": "2026-07-22T12:05:00Z" }, "meta": { "idempotent_replay": false } } ``` **Errors:** `400`, `401`, `403`, `404`, `409`, `422`, `429`, `500` ### `POST /api/v1/channels/{channel}/templates/{template}/archive` **Operation ID:** `archiveTemplate` **Purpose:** Archive a custom Channel template. **Abilities:** `templates:write` **Write safety:** idempotency `required`; concurrency `required`; retry `same-key`. **Parameters** - `channel` — path, required - `template` — path, required - `IdempotencyKey` (shared header parameter) - `IfMatch` (shared header parameter) **Response `200` example** ```json { "data": { "id": 22, "kind": "custom", "key": null, "name": "My explainer", "slug": "my-explainer", "category": "custom", "description": null, "prompt": "Write a clear structured explainer with a compelling opening and concrete examples for the intended audience.", "is_default": false, "archived": true, "mutable": true, "revision": "template-r1-archived", "created_at": "2026-07-22T12:00:00Z", "updated_at": "2026-07-22T12:05:00Z" }, "meta": { "idempotent_replay": false } } ``` **Errors:** `400`, `401`, `403`, `404`, `409`, `422`, `429`, `500` ### `POST /api/v1/channels/{channel}/templates/{template}/restore` **Operation ID:** `restoreTemplate` **Purpose:** Restore an archived custom Channel template. **Abilities:** `templates:write` **Write safety:** idempotency `required`; concurrency `required`; retry `same-key`. **Parameters** - `channel` — path, required - `template` — path, required - `IdempotencyKey` (shared header parameter) - `IfMatch` (shared header parameter) **Response `200` example** ```json { "data": { "id": 22, "kind": "custom", "key": null, "name": "My explainer", "slug": "my-explainer", "category": "custom", "description": null, "prompt": "Write a clear structured explainer with a compelling opening and concrete examples for the intended audience.", "is_default": false, "archived": false, "mutable": true, "revision": "template-r1-restored", "created_at": "2026-07-22T12:00:00Z", "updated_at": "2026-07-22T12:10:00Z" }, "meta": { "idempotent_replay": false } } ``` **Errors:** `400`, `401`, `403`, `404`, `409`, `422`, `429`, `500` ## Thumbnails ### `GET /api/v1/channels/{channel}/thumbnails/generations` **Operation ID:** `listThumbnailGenerations` **Purpose:** List Thumbnail Generations. **Abilities:** `scripts:read`, `thumbnails:read` **Parameters** - `channel` — path, required - `source_type` — query, optional - `page` — query, optional **Response `200` example** ```json { "success": true, "data": [ { "run_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d", "status": "completed", "source_type": "api_generate", "idea_id": 42, "output_urls": [ "https://subscribr.ai/storage/thumbnails/9b1deb4d_v1.png" ], "created_at": "2026-02-27T10:30:00Z" } ], "meta": { "current_page": 1, "last_page": 3, "per_page": 15, "total": 42 } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `POST /api/v1/channels/{channel}/thumbnails/generations` **Operation ID:** `createThumbnailGeneration` **Purpose:** Create Thumbnail Generation. **Abilities:** `scripts:write`, `thumbnails:write` **Write safety:** idempotency `unsupported`; concurrency `unsupported`; retry `never`. **Parameters** - `channel` — path, required **Request example** ```json { "idea_id": 42, "num_variations": 3, "callback_url": "https://partner.example.com/subscribr/thumbnail-callback", "callback_secret": "whsec_thumbnail_partner_secret" } ``` **Response `202` example** ```json { "success": true, "data": { "run_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d", "run_ids": [ "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d" ], "status": "queued" } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `GET /api/v1/channels/{channel}/thumbnails/generations/{runId}` **Operation ID:** `getThumbnailGeneration` **Purpose:** Get Thumbnail Generation. **Abilities:** `scripts:read`, `thumbnails:read` **Parameters** - `channel` — path, required - `runId` — path, required **Response `200` example** ```json { "success": true, "data": { "run_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d", "status": "completed", "idea_id": null, "output_urls": [ "https://subscribr.ai/storage/thumbnails/9b1deb4d_v1.png", "https://subscribr.ai/storage/thumbnails/9b1deb4d_v2.png" ], "created_at": "2026-02-27T10:30:00Z", "updated_at": "2026-02-27T10:30:45Z" } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `GET /api/v1/channels/{channel}/thumbnails/board` **Operation ID:** `getThumbnailBoard` **Purpose:** Get Thumbnail Board. **Abilities:** `thumbnails:read` **Parameters** - `channel` — path, required **Response `200` example** ```json { "success": true, "data": { "channel_id": 1, "board_id": 12, "studio_url": "https://subscribr.ai/channels/1/thumbnails", "credits_remaining": 42, "items": [ { "id": 311, "type": "image", "status": "ready", "x": 48, "y": 128, "width": 320, "height": 180, "frame_id": 310, "url": "https://subscribr.ai/storage/thumbnails/boards/311.png", "label": "How I fixed my retention", "source": "youtube_video" } ] } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `POST /api/v1/channels/{channel}/thumbnails/board/images` **Operation ID:** `addThumbnailBoardImages` **Purpose:** Add Thumbnail Board Images. **Abilities:** `thumbnails:write` **Write safety:** idempotency `unsupported`; concurrency `unsupported`; retry `never`. **Parameters** - `channel` — path, required **Request example** ```json { "source": "urls", "urls": [ "https://example.com/reference.png" ], "usage": "style", "label": "Competitor picks" } ``` **Response `200` example** ```json { "success": true, "data": { "board_id": 12, "items": [ { "id": 311, "type": "image", "status": "ready", "x": 48, "y": 128, "width": 320, "height": 180, "frame_id": 310, "url": "https://subscribr.ai/storage/thumbnails/boards/311.png", "label": "How I fixed my retention", "source": "youtube_video" } ] } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `POST /api/v1/channels/{channel}/thumbnails/board/generations` **Operation ID:** `createThumbnailBoardGeneration` **Purpose:** Create Thumbnail Board Generation. **Abilities:** `thumbnails:write` **Write safety:** idempotency `required`; concurrency `optional`; retry `same-key`. **Parameters** - `channel` — path, required - `IdempotencyKey` (shared header parameter) - `IfMatch` (shared header parameter) **Request example** ```json { "prompt": "Shocked face pointing at a giant chart", "reference_item_ids": [ 311 ], "variations": 2, "allow_text": false } ``` **Response `200` example** ```json { "success": true, "data": { "board_id": 12, "credits_spent": 2, "credits_remaining": 40, "items": [ { "id": 312, "type": "image", "status": "generating", "x": 48, "y": 360, "width": 320, "height": 180, "prompt": "Shocked face pointing at a giant chart", "source": "generation" } ], "note": "Rendering is asynchronous (typically 10-60 seconds per image). Poll GET /thumbnails/board until these items turn \"ready\"." } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `POST /api/v1/channels/{channel}/thumbnails/board/edits` **Operation ID:** `editThumbnailBoardImage` **Purpose:** Edit Thumbnail Board Image. **Abilities:** `thumbnails:write` **Write safety:** idempotency `required`; concurrency `optional`; retry `same-key`. **Parameters** - `channel` — path, required - `IdempotencyKey` (shared header parameter) - `IfMatch` (shared header parameter) **Request example** ```json { "item_id": 312, "instruction": "Remove the text", "region": { "x": 0.05, "y": 0.55, "width": 0.6, "height": 0.35 } } ``` **Response `200` example** ```json { "success": true, "data": { "board_id": 12, "credits_spent": 1, "credits_remaining": 39, "items": [ { "id": 318, "type": "image", "status": "generating", "x": 392, "y": 360, "width": 320, "height": 180, "prompt": "Remove the text", "source": "generation" } ], "note": "The edit renders asynchronously as a new item beside the original, which is left unchanged. Poll GET /thumbnails/board until it turns \"ready\"." } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `POST /api/v1/channels/{channel}/thumbnails/board/text` **Operation ID:** `setThumbnailBoardText` **Purpose:** Set Thumbnail Board Text. **Abilities:** `thumbnails:write` **Write safety:** idempotency `unsupported`; concurrency `unsupported`; retry `never`. **Parameters** - `channel` — path, required **Request example** ```json { "content": "I WAS WRONG", "over_item_id": 311, "size": 64 } ``` **Response `200` example** ```json { "success": true, "data": { "board_id": 12, "item": { "id": 313, "type": "text", "status": "ready", "x": 62, "y": 140, "width": 292, "height": 60, "content": "I WAS WRONG", "source": "agent" } } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `POST /api/v1/channels/{channel}/thumbnails/board/export` **Operation ID:** `exportThumbnailBoardImage` **Purpose:** Export Thumbnail Board Image. **Abilities:** `thumbnails:write` **Write safety:** idempotency `unsupported`; concurrency `unsupported`; retry `never`. **Parameters** - `channel` — path, required **Request example** ```json { "item_id": 311 } ``` **Response `200` example** ```json { "success": true, "data": { "board_id": 12, "url": "https://subscribr.ai/storage/thumbnails/boards/export-314.png", "item": { "id": 314, "type": "image", "status": "ready", "x": 408, "y": 128, "width": 320, "height": 180, "url": "https://subscribr.ai/storage/thumbnails/boards/export-314.png", "source": "export" }, "overlays_flattened": 1 } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `POST /api/v1/channels/{channel}/thumbnails/board/assign-to-script` **Operation ID:** `assignThumbnailBoardImageToScript` **Purpose:** Assign Thumbnail Board Image To Script. **Abilities:** `thumbnails:write` **Write safety:** idempotency `unsupported`; concurrency `unsupported`; retry `never`. **Parameters** - `channel` — path, required **Request example** ```json { "item_id": 314, "script_id": 88 } ``` **Response `200` example** ```json { "success": true, "data": { "script_id": 88, "attachment_id": 402, "thumbnail_url": "https://subscribr.ai/storage/kanban-attachments/402.png" } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `GET /api/v1/team/thumbnails/usage` **Operation ID:** `getThumbnailUsage` **Purpose:** Get Thumbnail Usage. **Abilities:** `scripts:read`, `thumbnails:read` **Response `200` example** ```json { "success": true, "data": { "eligible": true, "free_pool": { "limit": 5, "used": 2, "reserved": 1, "remaining": 2, "next_reset": "2026-04-01" }, "addon_pool": { "limit": 50, "used": 10, "reserved": 0, "remaining": 40, "next_reset": "2026-04-15" }, "pack_pool": { "limit": 100, "used": 5, "reserved": 0, "remaining": 95, "next_reset": null }, "total_remaining": 137 } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ## Video ### `GET /api/v1/video/capabilities` **Operation ID:** `videoListCapabilities` **Purpose:** List available Subscribr Video capabilities. **Abilities:** `video:read` **Response `200` example** ```json { "version": "1.0.0", "data": [] } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500`, `503` ### `GET /api/v1/video/channels` **Operation ID:** `videoListChannels` **Purpose:** List Subscribr Video channels for the current team. **Abilities:** `video:read` **Response `200` example** ```json { "data": [ { "id": "stch_example", "display_name": "Example", "handle": "example", "origin": { "kind": "standalone", "main_channel_id": null }, "mode": "faceless", "configuration": { "voice": { "selection": "catalog", "resource_id": null, "identity_status": "unresolved", "speaking_rate": 1.08, "delivery_mode": null }, "presenter": { "avatar": { "selection": "none", "resource_id": null, "identity_status": "none" }, "look": { "selection": "none", "resource_id": null, "identity_status": "none" }, "type": null, "layout": { "style": null, "position": null } }, "theme": { "id": "academic_explainer", "overrides": { "brand_accent_color": null, "brand_highlight_color": null, "evidence_label_style": null, "section_reset_treatment": null, "data_count_treatment": null, "archival_treatment": null } }, "pacing": { "pace_profile": null, "structure_hint": null, "slideshow_max_seconds": null }, "captions": { "enabled": true, "style": "default" }, "music": { "enabled": false, "sfx_family": null }, "post_processing": { "profile": null }, "reference_media": { "attachment_count": 0, "identity_status": "none", "resource_ids": [] }, "style": { "configured": true }, "active": true }, "readiness": { "status": "ready", "missing_requirements": [] }, "configuration_revision": 1, "created_at": "2026-07-29T00:00:00+00:00", "updated_at": "2026-07-29T00:00:00+00:00" } ] } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500`, `503` ### `GET /api/v1/video/channels/{videoChannel}` **Operation ID:** `videoGetChannel` **Purpose:** Get a Subscribr Video channel for the current team. **Abilities:** `video:read` **Parameters** - `videoChannel` — path, required **Response `200` example** ```json { "data": { "id": "stch_example", "display_name": "Example", "handle": "example", "origin": { "kind": "standalone", "main_channel_id": null }, "mode": "faceless", "configuration": { "voice": { "selection": "catalog", "resource_id": null, "identity_status": "unresolved", "speaking_rate": 1.08, "delivery_mode": null }, "presenter": { "avatar": { "selection": "none", "resource_id": null, "identity_status": "none" }, "look": { "selection": "none", "resource_id": null, "identity_status": "none" }, "type": null, "layout": { "style": null, "position": null } }, "theme": { "id": "academic_explainer", "overrides": { "brand_accent_color": null, "brand_highlight_color": null, "evidence_label_style": null, "section_reset_treatment": null, "data_count_treatment": null, "archival_treatment": null } }, "pacing": { "pace_profile": null, "structure_hint": null, "slideshow_max_seconds": null }, "captions": { "enabled": true, "style": "default" }, "music": { "enabled": false, "sfx_family": null }, "post_processing": { "profile": null }, "reference_media": { "attachment_count": 0, "identity_status": "none", "resource_ids": [] }, "style": { "configured": true }, "active": true }, "readiness": { "status": "ready", "missing_requirements": [] }, "configuration_revision": 1, "created_at": "2026-07-29T00:00:00+00:00", "updated_at": "2026-07-29T00:00:00+00:00" } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500`, `503` ### `GET /api/v1/video/voices` **Operation ID:** `videoListVoices` **Purpose:** List custom voices available to the current team. **Abilities:** `video:read` **Parameters** - `page` — query, optional - `per_page` — query, optional **Response `200` example** ```json { "data": [], "pagination": { "current_page": 1, "per_page": 20, "total": 0, "last_page": 1 } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500`, `503` ### `GET /api/v1/video/voices/{voice}` **Operation ID:** `videoGetVoice` **Purpose:** Get a custom voice available to the current team. **Abilities:** `video:read` **Parameters** - `voice` — path, required **Response `200` example** ```json { "data": { "id": "820e8400-e29b-41d4-a716-446655440003", "kind": "custom_voice", "name": "Narration voice", "state": "ready", "allowed_actions": [] } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500`, `503` ### `GET /api/v1/video/avatars` **Operation ID:** `videoListAvatars` **Purpose:** List custom avatars available to the current team. **Abilities:** `video:read` **Parameters** - `page` — query, optional - `per_page` — query, optional **Response `200` example** ```json { "data": [], "pagination": { "current_page": 1, "per_page": 20, "total": 0, "last_page": 1 } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500`, `503` ### `GET /api/v1/video/avatars/{avatar}` **Operation ID:** `videoGetAvatar` **Purpose:** Get a custom avatar available to the current team. **Abilities:** `video:read` **Parameters** - `avatar` — path, required **Response `200` example** ```json { "data": { "id": "820e8400-e29b-41d4-a716-446655440002", "kind": "custom_avatar", "name": "Backup host", "state": "failed", "allowed_actions": [ "retry_training" ] } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500`, `503` ### `GET /api/v1/video/media-assets` **Operation ID:** `videoListMediaAssets` **Purpose:** List reference media available to the current team. **Abilities:** `video:read` **Parameters** - `page` — query, optional - `per_page` — query, optional **Response `200` example** ```json { "data": [], "pagination": { "current_page": 1, "per_page": 20, "total": 0, "last_page": 1 } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500`, `503` ### `GET /api/v1/video/media-assets/{mediaAsset}` **Operation ID:** `videoGetMediaAsset` **Purpose:** Get reference media available to the current team. **Abilities:** `video:read` **Parameters** - `mediaAsset` — path, required **Response `200` example** ```json { "data": { "id": "820e8400-e29b-41d4-a716-446655440006", "kind": "reference_media", "name": "Retry reference", "state": "failed", "allowed_actions": [ "retry_processing" ] } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500`, `503` ### `GET /api/v1/video/projects` **Operation ID:** `videoListProjects` **Purpose:** List Subscribr Video projects. **Abilities:** `video:read` **Response `200` example** ```json { "data": [ { "id": "proj_01hz3k9pb1z7c5m2r6n0y4x2a2", "title": "Example title", "status": "complete", "channel_id": "stch_example", "created_at": "2026-08-01T00:00:00Z", "current_artifact": { "revision": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "published_at": "2026-08-02T00:00:00Z" } } ], "pagination": { "current_page": 1, "per_page": 20, "total": 1, "last_page": 1 } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `POST /api/v1/video/projects` **Operation ID:** `videoCreateVideo` **Purpose:** Create a Subscribr Video project. **Abilities:** `video:generate` **Write safety:** idempotency `required`; concurrency `unsupported`; retry `same-key`. **Parameters** - `IdempotencyKey` (shared header parameter) **Request example** ```json { "name": "Example title", "script": "This is an example script for a short video." } ``` **Response `202` example** ```json { "operation": { "id": "9f8b6b0e-6b8e-4b8e-8b8e-6b8e4b8e8b8f", "type": "video_generate", "status": "running", "progress": 10, "result": null, "error": null, "domain_resource": { "type": "video_project", "id": "proj_01hz3k9pb1z7c5m2r6n0y4x2a2" } } } ``` **Errors:** `409`, `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `GET /api/v1/video/projects/{project}` **Operation ID:** `videoGetProject` **Purpose:** Get a Subscribr Video project. **Abilities:** `video:read` **Parameters** - `project` — path, required **Response `200` example** ```json { "data": { "id": "proj_01hz3k9pb1z7c5m2r6n0y4x2a2", "title": "Example title", "status": "complete", "channel_id": "stch_example", "created_at": "2026-08-01T00:00:00Z", "current_artifact": { "revision": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "published_at": "2026-08-02T00:00:00Z" } } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `GET /api/v1/video/projects/{project}/download` **Operation ID:** `videoGetProjectDownload` **Purpose:** Get a Subscribr Video project's download URL. **Abilities:** `video:read` **Parameters** - `project` — path, required **Response `200` example** ```json { "data": { "download_url": "https://cdn.video.subscribr.ai/proj_01.mp4?sig=abc", "expires_at": "2026-08-27T13:00:00Z" } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `GET /api/v1/video/projects/{project}/editable-content` **Operation ID:** `videoGetEditableContent` **Purpose:** Get a Subscribr Video project's editable Review & Fix content. **Abilities:** `video:read` **Parameters** - `project` — path, required **Response `200` example** ```json { "data": { "edit_session": { "status": "draft", "editable": true }, "edit_availability": { "can_apply": true, "can_start_new_pass": true, "edit_window_ends_at": "2026-09-01T12:00:00Z", "explanation": "You can stage and apply one revision pass." }, "overlays": [], "visual_blocks": [ { "key": "block_1", "available_actions": [ "replace_with_media" ], "replace_with_media_paid": false } ], "settings": { "captions": { "enabled": true, "style": "default" }, "music": { "removal_available": true } } } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `GET /api/v1/video/projects/{project}/revision-manifest` **Operation ID:** `videoGetRevisionManifest` **Purpose:** Get a Subscribr Video project's revision manifest. **Abilities:** `video:read` **Parameters** - `project` — path, required - `cursor` — query, optional - `per_page` — query, optional **Response `200` example** ```json { "data": { "revision": { "number": 3, "status": "draft" }, "items": [ { "id": "item_1", "overlay_id": "ov_1", "label": "Add on-screen text", "scope": "moment", "status": "ready", "status_label": "Ready to apply", "start_time": 1, "end_time": 2, "operation": "add", "template": "lower_third", "inputs": { "text": "Hello" } } ] }, "meta": { "next_cursor": null } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `GET /api/v1/video/projects/{project}/overlay-templates` **Operation ID:** `videoListOverlayTemplates` **Purpose:** List overlay templates available for a Subscribr Video project. **Abilities:** `video:read` **Parameters** - `project` — path, required **Response `200` example** ```json { "data": [ { "id": "lower_third", "label": "Lower third", "description": "A lower-third caption overlay.", "input_fields": [ { "key": "text", "label": "Text", "type": "string", "required": true, "max_chars": 60 } ], "preview_url": "/api/v1/videos/proj_01hz3k9pb1z7c5m2r6n0y4x2a2/revision-overlay-templates/lower_third/preview" } ] } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `GET /api/v1/video/projects/{project}/quality-report` **Operation ID:** `videoGetQualityReport` **Purpose:** Get a Subscribr Video project's latest quality report. **Abilities:** `video:read` **Parameters** - `project` — path, required **Response `200` example** ```json { "data": { "status": "ready", "artifact": { "revision": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "duration_seconds": 898.2 }, "overall_status": "pass", "visual_status": "pass", "audio_status": "pass", "measured_at": "2026-08-27T12:05:00Z", "findings": [ { "id": "quality_review.duration_parity_failed", "category": "timing", "severity": "warning", "message": "The captioned duration differs from the audio track by 0.4s.", "start_time": 12.4, "end_time": 15 } ], "summary": { "count": 1, "severe_count": 0 } } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `GET /api/v1/video/projects/{project}/revision/passes/{pass}` **Operation ID:** `videoGetRevisionPass` **Purpose:** Get one Subscribr Video revision pass. **Abilities:** `video:read` **Parameters** - `project` — path, required - `pass` — path, required **Response `200` example** ```json { "data": { "id": "pass_01hz3k9pb1z7c5m2r6n0y4x2a2", "number": 3, "status": "complete", "applied_at": "2026-08-27T12:00:00Z", "error": null, "artifact": { "revision": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", "published_at": "2026-08-27T12:01:00Z" }, "download": { "available": true, "endpoint": "/api/v1/video/projects/proj_01hz3k9pb1z7c5m2r6n0y4x2a2/download" }, "quality_review": { "status": "ready" } } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `POST /api/v1/video/projects/{project}/revision/overlays` **Operation ID:** `videoAddOverlay` **Purpose:** Add a staged overlay to a Subscribr Video revision. **Abilities:** `video:edit` **Write safety:** idempotency `required`; concurrency `required`; retry `same-key`. **Parameters** - `IdempotencyKey` (shared header parameter) - `IfMatch` (shared header parameter) - `project` — path, required **Request example** ```json { "template": "lower_third", "inputs": { "text": "New product launch" }, "playhead_time": 42 } ``` **Response `201` example** ```json { "data": { "id": "item_01hz3k9pb1z7c5m2r6n0y4x2a2", "overlay_id": "ov_01hz3k9pb1z7c5m2r6n0y4x2a2", "revision_item_id": "item_01hz3k9pb1z7c5m2r6n0y4x2a2", "status": "generating", "start_time": 41, "end_time": 43, "template": "lower_third" }, "meta": { "idempotent_replay": false } } ``` **Errors:** `400`, `401`, `403`, `404`, `409`, `422`, `429`, `500` ### `DELETE /api/v1/video/projects/{project}/revision/overlays/{item}` **Operation ID:** `videoRemoveStagedOverlay` **Purpose:** Remove a staged overlay from a Subscribr Video revision. **Abilities:** `video:edit` **Write safety:** idempotency `required`; concurrency `required`; retry `same-key`. **Parameters** - `IdempotencyKey` (shared header parameter) - `IfMatch` (shared header parameter) - `project` — path, required - `item` — path, required **Response `200` example** ```json { "data": { "deleted": true }, "meta": { "idempotent_replay": false } } ``` **Errors:** `400`, `401`, `403`, `404`, `409`, `422`, `429`, `500` ### `PATCH /api/v1/video/projects/{project}/revision/published-overlays/{overlay}` **Operation ID:** `videoUpdateOverlay` **Purpose:** Update a published overlay in a Subscribr Video revision. **Abilities:** `video:edit` **Write safety:** idempotency `required`; concurrency `required`; retry `same-key`. **Parameters** - `IdempotencyKey` (shared header parameter) - `IfMatch` (shared header parameter) - `project` — path, required - `overlay` — path, required **Request example** ```json { "inputs": { "text": "Updated overlay text" } } ``` **Response `200` example** ```json { "data": { "id": "item_01hz3k9pb1z7c5m2r6n0y4x2a3", "action": "update_overlay", "status": "generating" }, "meta": { "idempotent_replay": false } } ``` **Errors:** `400`, `401`, `403`, `404`, `409`, `422`, `429`, `500` ### `DELETE /api/v1/video/projects/{project}/revision/published-overlays/{overlay}` **Operation ID:** `videoRemoveOverlay` **Purpose:** Remove a published overlay from a Subscribr Video revision. **Abilities:** `video:edit` **Write safety:** idempotency `required`; concurrency `required`; retry `same-key`. **Parameters** - `IdempotencyKey` (shared header parameter) - `IfMatch` (shared header parameter) - `project` — path, required - `overlay` — path, required **Response `200` example** ```json { "data": { "deleted": true }, "meta": { "idempotent_replay": false } } ``` **Errors:** `400`, `401`, `403`, `404`, `409`, `422`, `429`, `500` ### `PUT /api/v1/video/projects/{project}/revision/captions` **Operation ID:** `videoUpdateCaptions` **Purpose:** Update caption settings in a Subscribr Video revision. **Abilities:** `video:edit` **Write safety:** idempotency `required`; concurrency `required`; retry `same-key`. **Parameters** - `IdempotencyKey` (shared header parameter) - `IfMatch` (shared header parameter) - `project` — path, required **Request example** ```json { "enabled": true, "style": "default" } ``` **Response `200` example** ```json { "data": { "id": "item_01hz3k9pb1z7c5m2r6n0y4x2a4", "action": "update_captions", "status": "ready" }, "meta": { "idempotent_replay": false } } ``` **Errors:** `400`, `401`, `403`, `404`, `409`, `422`, `429`, `500` ### `PUT /api/v1/video/projects/{project}/revision/music` **Operation ID:** `videoRemoveMusic` **Purpose:** Update background music removal in a Subscribr Video revision. **Abilities:** `video:edit` **Write safety:** idempotency `required`; concurrency `required`; retry `same-key`. **Parameters** - `IdempotencyKey` (shared header parameter) - `IfMatch` (shared header parameter) - `project` — path, required **Request example** ```json { "remove": true } ``` **Response `200` example** ```json { "data": { "id": "item_01hz3k9pb1z7c5m2r6n0y4x2a5", "action": "music_removal", "status": "ready" }, "meta": { "idempotent_replay": false } } ``` **Errors:** `400`, `401`, `403`, `404`, `409`, `422`, `429`, `500` ### `PATCH /api/v1/video/projects/{project}/revision/slide-text` **Operation ID:** `videoEditSlideText` **Purpose:** Edit slide text in a Subscribr Video revision. **Abilities:** `video:edit` **Write safety:** idempotency `required`; concurrency `required`; retry `same-key`. **Parameters** - `IdempotencyKey` (shared header parameter) - `IfMatch` (shared header parameter) - `project` — path, required **Request example** ```json { "block_key": "slide_3", "field_edits": [ { "key": "headline", "value": "New headline" } ] } ``` **Response `200` example** ```json { "data": { "id": "item_01hz3k9pb1z7c5m2r6n0y4x2a6", "action": "edit_slide_text", "status": "ready" }, "meta": { "idempotent_replay": false } } ``` **Errors:** `400`, `401`, `403`, `404`, `409`, `422`, `429`, `500` ### `PUT /api/v1/video/projects/{project}/revision/regenerate-visual` **Operation ID:** `videoRegenerateVisual` **Purpose:** Regenerate a visual block in a Subscribr Video revision. **Abilities:** `video:edit` **Write safety:** idempotency `required`; concurrency `required`; retry `same-key`. **Parameters** - `IdempotencyKey` (shared header parameter) - `IfMatch` (shared header parameter) - `project` — path, required **Request example** ```json { "block_key": "slide_5", "prompt": "A wide shot of a modern kitchen" } ``` **Response `200` example** ```json { "data": { "id": "item_01hz3k9pb1z7c5m2r6n0y4x2a7", "action": "regenerate_visual", "status": "generating" }, "meta": { "idempotent_replay": false } } ``` **Errors:** `400`, `401`, `403`, `404`, `409`, `422`, `429`, `500` ### `PUT /api/v1/video/projects/{project}/revision/replace-with-media` **Operation ID:** `videoReplaceWithMedia` **Purpose:** Replace a visual block with a media-library asset in a Subscribr Video revision. **Abilities:** `video:edit` **Write safety:** idempotency `required`; concurrency `required`; retry `same-key`. **Parameters** - `IdempotencyKey` (shared header parameter) - `IfMatch` (shared header parameter) - `project` — path, required **Request example** ```json { "block_key": "slide_5", "media_asset_id": "9c1b6a1a-8e2b-4b8a-9a1e-2f7a5c6d9e3b" } ``` **Response `200` example** ```json { "data": { "id": "item_01hz3k9pb1z7c5m2r6n0y4x2a7", "action": "replace_with_media", "status": "ready", "cropped": false }, "meta": { "idempotent_replay": false } } ``` **Errors:** `400`, `401`, `403`, `404`, `409`, `422`, `429`, `500` ### `PUT /api/v1/video/projects/{project}/revision/presenter` **Operation ID:** `videoShowPresenter` **Purpose:** Switch a visual block to the presenter in a Subscribr Video revision. **Abilities:** `video:edit` **Write safety:** idempotency `required`; concurrency `required`; retry `same-key`. **Parameters** - `IdempotencyKey` (shared header parameter) - `IfMatch` (shared header parameter) - `project` — path, required **Request example** ```json { "block_key": "slide_7", "note": "Show the presenter here instead." } ``` **Response `200` example** ```json { "data": { "id": "item_01hz3k9pb1z7c5m2r6n0y4x2a8", "action": "use_avatar_only", "status": "generating" }, "meta": { "idempotent_replay": false } } ``` **Errors:** `400`, `401`, `403`, `404`, `409`, `422`, `429`, `500` ### `DELETE /api/v1/video/projects/{project}/revision/items/{item}` **Operation ID:** `videoDiscardEdit` **Purpose:** Discard a staged edit from a Subscribr Video revision. **Abilities:** `video:edit` **Write safety:** idempotency `required`; concurrency `required`; retry `same-key`. **Parameters** - `IdempotencyKey` (shared header parameter) - `IfMatch` (shared header parameter) - `project` — path, required - `item` — path, required **Response `200` example** ```json { "data": { "deleted": true }, "meta": { "idempotent_replay": false } } ``` **Errors:** `400`, `401`, `403`, `404`, `409`, `422`, `429`, `500` ### `POST /api/v1/video/projects/{project}/revision/apply` **Operation ID:** `videoApplyRevision` **Purpose:** Apply a Subscribr Video revision and publish a new version. **Abilities:** `video:publish` **Write safety:** idempotency `required`; concurrency `required`; retry `same-key`. **Parameters** - `IdempotencyKey` (shared header parameter) - `IfMatch` (shared header parameter) - `project` — path, required **Response `202` example** ```json { "operation": { "id": "9f8b6b0e-6b8e-4b8e-8b8e-6b8e4b8e8b8e", "type": "video_apply_revision", "status": "running", "progress": 10, "result": null, "error": null, "domain_resource": { "type": "video_revision_pass", "id": "pass_01hz3k9pb1z7c5m2r6n0y4x2a2" } } } ``` **Errors:** `400`, `401`, `403`, `404`, `409`, `422`, `429`, `500` ### `POST /api/v1/video/projects/quote` **Operation ID:** `videoQuoteVideo` **Purpose:** Quote a Subscribr Video generation. **Abilities:** `video:generate` **Write safety:** idempotency `unsupported`; concurrency `unsupported`; retry `never`. **Request example** ```json { "name": "Example title", "script": "This is an example script for a short video." } ``` **Response `200` example** ```json { "data": { "dry_run": true, "estimated_seconds": 120, "required_credits": 2 } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `POST /api/v1/video/projects/{project}/cancel` **Operation ID:** `videoCancelVideo` **Purpose:** Cancel a Subscribr Video project. **Abilities:** `video:generate` **Write safety:** idempotency `required`; concurrency `unsupported`; retry `same-key`. **Parameters** - `IdempotencyKey` (shared header parameter) - `project` — path, required **Request example** ```json { "reason": "No longer needed" } ``` **Response `200` example** ```json { "data": { "id": "proj_01hz3k9pb1z7c5m2r6n0y4x2a2", "title": "Example title", "status": "cancelled", "channel_id": "stch_example", "created_at": "2026-08-01T00:00:00Z", "current_artifact": null }, "meta": { "idempotent_replay": false } } ``` **Errors:** `409`, `400`, `401`, `403`, `404`, `422`, `429`, `500` ## Voices ### `GET /api/v1/channels/{channel}/voices` **Operation ID:** `listChannelVoices` **Purpose:** List Channel Voices. **Abilities:** `voices:read` **Parameters** - `channel` — path, required **Response `200` example** ```json { "data": [ { "id": "2d3b57bd-916d-4ce2-a85b-a65dc8fc97b4", "name": "Default Voice", "framework_version": 2, "schema_version": 2, "checksum": "9b2d", "revision": "voice-r1-example", "writable": true, "profile": { "writing_style_analysis": [] }, "created_at": "2026-07-22T12:00:00Z", "updated_at": "2026-07-22T12:00:00Z" } ], "meta": { "default_voice_id": "2d3b57bd-916d-4ce2-a85b-a65dc8fc97b4", "truncated": false } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `POST /api/v1/channels/{channel}/voices/validate` **Operation ID:** `validateVoiceProfile` **Purpose:** Validate and canonicalize a complete Voice Profile v2 without mutating data. **Abilities:** `voices:write` **Write safety:** idempotency `unsupported`; concurrency `unsupported`; retry `revalidate`. **Parameters** - `channel` — path, required **Request example** ```json { "intent": "create", "name": "Practical guide", "profile": { "writing_style_analysis": { "speaker_archetype": { "label": "Practical guide", "description": "Calm expert.", "axes": { "age_vibe": "experienced peer", "profession_archetype": "strategist", "temperament": "calm", "authority_posture": "confident" } }, "stance_and_relationship": { "narrative_person": "second person", "intimacy_distance": "trusted peer", "certainty_level": "Names uncertainty.", "audience_model": "Experienced creators." }, "delivery_recipe": { "cadence": "Short claims.", "energy": "Warm.", "pacing_and_emphasis": [ "Front-load the point." ] }, "rhetorical_toolkit": { "hook_patterns": [ "Open with a misconception." ], "transitions": [ "Here is the useful part." ], "explanation_patterns": [ "Make it concrete." ], "storytelling_patterns": [ "Start at the decision." ], "cta_patterns": [], "analogy_and_evidence": "Use one analogy.", "humor_and_empathy": "Keep humor light." }, "diction_and_syntax": { "vocabulary_level": "conversational", "word_complexity": "Prefer short words.", "sentence_shape": "Mix short and medium sentences.", "preferred_constructions": [ "Here is the tradeoff." ], "avoid": [ "Empty jargon." ] }, "phrase_kit": { "uses": [], "avoid": [], "replacements": [] }, "jargon_policy": { "allow": [], "explain_with": [ "a tiny example" ] }, "formatting_directives": [ "Use short paragraphs." ], "do_dont": { "do": [ "Lead with value." ], "dont": [ "Invent facts." ], "never_does": [ "Hide uncertainty." ] }, "locale_and_dialect": "Natural American English.", "thinking_style": "Test conclusions against evidence.", "spoken_patterns": { "common_phrases": [], "starter_words": [], "transition_phrases": [] }, "rewriter_directives": [ "Address the listener as you." ], "adherence_checklist": [ "No invented specifics." ], "lexical_glossary": [], "example_paragraph": "Start with the decision your viewer needs to make. Then give them only the evidence that changes it.", "style_examples": [ "Start with the decision your viewer needs to make. Then build the explanation around the evidence that changes that decision." ] } } } ``` **Response `200` example** ```json { "data": { "receipt": "vr2.current.opaque-token", "expires_at": "2026-07-22T12:10:00Z", "voice_id": "2d3b57bd-916d-4ce2-a85b-a65dc8fc97b4", "schema_version": 2, "checksum": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", "expected_revision": null, "normalized": { "writing_style_analysis": { "speaker_archetype": { "label": "Practical guide", "description": "Calm expert.", "axes": { "age_vibe": "experienced peer", "profession_archetype": "strategist", "temperament": "calm", "authority_posture": "confident" } }, "stance_and_relationship": { "narrative_person": "second person", "intimacy_distance": "trusted peer", "certainty_level": "Names uncertainty.", "audience_model": "Experienced creators." }, "delivery_recipe": { "cadence": "Short claims.", "energy": "Warm.", "pacing_and_emphasis": [ "Front-load the point." ] }, "rhetorical_toolkit": { "hook_patterns": [ "Open with a misconception." ], "transitions": [ "Here is the useful part." ], "explanation_patterns": [ "Make it concrete." ], "storytelling_patterns": [ "Start at the decision." ], "cta_patterns": [], "analogy_and_evidence": "Use one analogy.", "humor_and_empathy": "Keep humor light." }, "diction_and_syntax": { "vocabulary_level": "conversational", "word_complexity": "Prefer short words.", "sentence_shape": "Mix short and medium sentences.", "preferred_constructions": [ "Here is the tradeoff." ], "avoid": [ "Empty jargon." ] }, "phrase_kit": { "uses": [], "avoid": [], "replacements": [] }, "jargon_policy": { "allow": [], "explain_with": [ "a tiny example" ] }, "formatting_directives": [ "Use short paragraphs." ], "do_dont": { "do": [ "Lead with value." ], "dont": [ "Invent facts." ], "never_does": [ "Hide uncertainty." ] }, "locale_and_dialect": "Natural American English.", "thinking_style": "Test conclusions against evidence.", "spoken_patterns": { "common_phrases": [], "starter_words": [], "transition_phrases": [] }, "rewriter_directives": [ "Address the listener as you." ], "adherence_checklist": [ "No invented specifics." ], "lexical_glossary": [], "example_paragraph": "Start with the decision your viewer needs to make. Then give them only the evidence that changes it.", "style_examples": [ "Start with the decision your viewer needs to make. Then build the explanation around the evidence that changes that decision." ] } }, "diff": [ "voice.created" ], "warnings": [] } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `POST /api/v1/channels/{channel}/voices/commit` **Operation ID:** `commitVoiceProfile` **Purpose:** Commit an exactly validated Voice Profile receipt. **Abilities:** `voices:write` **Write safety:** idempotency `required`; concurrency `optional`; retry `same-key`. **Parameters** - `channel` — path, required - `Idempotency-Key` — header, required - `If-Match` — header, optional **Request example** ```json { "receipt": "vr2.current.opaque-token", "profile": { "writing_style_analysis": { "speaker_archetype": { "label": "Practical guide", "description": "Calm expert.", "axes": { "age_vibe": "experienced peer", "profession_archetype": "strategist", "temperament": "calm", "authority_posture": "confident" } }, "stance_and_relationship": { "narrative_person": "second person", "intimacy_distance": "trusted peer", "certainty_level": "Names uncertainty.", "audience_model": "Experienced creators." }, "delivery_recipe": { "cadence": "Short claims.", "energy": "Warm.", "pacing_and_emphasis": [ "Front-load the point." ] }, "rhetorical_toolkit": { "hook_patterns": [ "Open with a misconception." ], "transitions": [ "Here is the useful part." ], "explanation_patterns": [ "Make it concrete." ], "storytelling_patterns": [ "Start at the decision." ], "cta_patterns": [], "analogy_and_evidence": "Use one analogy.", "humor_and_empathy": "Keep humor light." }, "diction_and_syntax": { "vocabulary_level": "conversational", "word_complexity": "Prefer short words.", "sentence_shape": "Mix short and medium sentences.", "preferred_constructions": [ "Here is the tradeoff." ], "avoid": [ "Empty jargon." ] }, "phrase_kit": { "uses": [], "avoid": [], "replacements": [] }, "jargon_policy": { "allow": [], "explain_with": [ "a tiny example" ] }, "formatting_directives": [ "Use short paragraphs." ], "do_dont": { "do": [ "Lead with value." ], "dont": [ "Invent facts." ], "never_does": [ "Hide uncertainty." ] }, "locale_and_dialect": "Natural American English.", "thinking_style": "Test conclusions against evidence.", "spoken_patterns": { "common_phrases": [], "starter_words": [], "transition_phrases": [] }, "rewriter_directives": [ "Address the listener as you." ], "adherence_checklist": [ "No invented specifics." ], "lexical_glossary": [], "example_paragraph": "Start with the decision your viewer needs to make. Then give them only the evidence that changes it.", "style_examples": [ "Start with the decision your viewer needs to make. Then build the explanation around the evidence that changes that decision." ] } } } ``` **Response `200` example** ```json { "data": { "id": "2d3b57bd-916d-4ce2-a85b-a65dc8fc97b4", "name": "Practical guide", "framework_version": 2, "schema_version": 2, "checksum": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", "revision": "voice-r1-example", "writable": true, "profile": { "writing_style_analysis": { "speaker_archetype": { "label": "Practical guide", "description": "Calm expert.", "axes": { "age_vibe": "experienced peer", "profession_archetype": "strategist", "temperament": "calm", "authority_posture": "confident" } }, "stance_and_relationship": { "narrative_person": "second person", "intimacy_distance": "trusted peer", "certainty_level": "Names uncertainty.", "audience_model": "Experienced creators." }, "delivery_recipe": { "cadence": "Short claims.", "energy": "Warm.", "pacing_and_emphasis": [ "Front-load the point." ] }, "rhetorical_toolkit": { "hook_patterns": [ "Open with a misconception." ], "transitions": [ "Here is the useful part." ], "explanation_patterns": [ "Make it concrete." ], "storytelling_patterns": [ "Start at the decision." ], "cta_patterns": [], "analogy_and_evidence": "Use one analogy.", "humor_and_empathy": "Keep humor light." }, "diction_and_syntax": { "vocabulary_level": "conversational", "word_complexity": "Prefer short words.", "sentence_shape": "Mix short and medium sentences.", "preferred_constructions": [ "Here is the tradeoff." ], "avoid": [ "Empty jargon." ] }, "phrase_kit": { "uses": [], "avoid": [], "replacements": [] }, "jargon_policy": { "allow": [], "explain_with": [ "a tiny example" ] }, "formatting_directives": [ "Use short paragraphs." ], "do_dont": { "do": [ "Lead with value." ], "dont": [ "Invent facts." ], "never_does": [ "Hide uncertainty." ] }, "locale_and_dialect": "Natural American English.", "thinking_style": "Test conclusions against evidence.", "spoken_patterns": { "common_phrases": [], "starter_words": [], "transition_phrases": [] }, "rewriter_directives": [ "Address the listener as you." ], "adherence_checklist": [ "No invented specifics." ], "lexical_glossary": [], "example_paragraph": "Start with the decision your viewer needs to make. Then give them only the evidence that changes it.", "style_examples": [ "Start with the decision your viewer needs to make. Then build the explanation around the evidence that changes that decision." ] } }, "created_at": "2026-07-22T12:00:00Z", "updated_at": "2026-07-22T12:05:00Z" }, "meta": { "idempotent_replay": false } } ``` **Response `201` example** ```json { "data": { "id": "2d3b57bd-916d-4ce2-a85b-a65dc8fc97b4", "name": "Practical guide", "framework_version": 2, "schema_version": 2, "checksum": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", "revision": "voice-r1-example", "writable": true, "profile": { "writing_style_analysis": { "speaker_archetype": { "label": "Practical guide", "description": "Calm expert.", "axes": { "age_vibe": "experienced peer", "profession_archetype": "strategist", "temperament": "calm", "authority_posture": "confident" } }, "stance_and_relationship": { "narrative_person": "second person", "intimacy_distance": "trusted peer", "certainty_level": "Names uncertainty.", "audience_model": "Experienced creators." }, "delivery_recipe": { "cadence": "Short claims.", "energy": "Warm.", "pacing_and_emphasis": [ "Front-load the point." ] }, "rhetorical_toolkit": { "hook_patterns": [ "Open with a misconception." ], "transitions": [ "Here is the useful part." ], "explanation_patterns": [ "Make it concrete." ], "storytelling_patterns": [ "Start at the decision." ], "cta_patterns": [], "analogy_and_evidence": "Use one analogy.", "humor_and_empathy": "Keep humor light." }, "diction_and_syntax": { "vocabulary_level": "conversational", "word_complexity": "Prefer short words.", "sentence_shape": "Mix short and medium sentences.", "preferred_constructions": [ "Here is the tradeoff." ], "avoid": [ "Empty jargon." ] }, "phrase_kit": { "uses": [], "avoid": [], "replacements": [] }, "jargon_policy": { "allow": [], "explain_with": [ "a tiny example" ] }, "formatting_directives": [ "Use short paragraphs." ], "do_dont": { "do": [ "Lead with value." ], "dont": [ "Invent facts." ], "never_does": [ "Hide uncertainty." ] }, "locale_and_dialect": "Natural American English.", "thinking_style": "Test conclusions against evidence.", "spoken_patterns": { "common_phrases": [], "starter_words": [], "transition_phrases": [] }, "rewriter_directives": [ "Address the listener as you." ], "adherence_checklist": [ "No invented specifics." ], "lexical_glossary": [], "example_paragraph": "Start with the decision your viewer needs to make. Then give them only the evidence that changes it.", "style_examples": [ "Start with the decision your viewer needs to make. Then build the explanation around the evidence that changes that decision." ] } }, "created_at": "2026-07-22T12:00:00Z", "updated_at": "2026-07-22T12:00:00Z" }, "meta": { "idempotent_replay": false } } ``` **Errors:** `400`, `401`, `403`, `404`, `409`, `422`, `429`, `500` ### `GET /api/v1/channels/{channel}/voices/{voice}` **Operation ID:** `getVoiceProfile` **Purpose:** Get a Channel Voice Profile. **Abilities:** `voices:read` **Parameters** - `channel` — path, required - `voice` — path, required **Response `200` example** ```json { "data": { "id": "2d3b57bd-916d-4ce2-a85b-a65dc8fc97b4", "name": "Practical guide", "framework_version": 2, "schema_version": 2, "checksum": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", "revision": "voice-r1-example", "writable": true, "profile": { "writing_style_analysis": { "speaker_archetype": { "label": "Practical guide", "description": "Calm expert.", "axes": { "age_vibe": "experienced peer", "profession_archetype": "strategist", "temperament": "calm", "authority_posture": "confident" } }, "stance_and_relationship": { "narrative_person": "second person", "intimacy_distance": "trusted peer", "certainty_level": "Names uncertainty.", "audience_model": "Experienced creators." }, "delivery_recipe": { "cadence": "Short claims.", "energy": "Warm.", "pacing_and_emphasis": [ "Front-load the point." ] }, "rhetorical_toolkit": { "hook_patterns": [ "Open with a misconception." ], "transitions": [ "Here is the useful part." ], "explanation_patterns": [ "Make it concrete." ], "storytelling_patterns": [ "Start at the decision." ], "cta_patterns": [], "analogy_and_evidence": "Use one analogy.", "humor_and_empathy": "Keep humor light." }, "diction_and_syntax": { "vocabulary_level": "conversational", "word_complexity": "Prefer short words.", "sentence_shape": "Mix short and medium sentences.", "preferred_constructions": [ "Here is the tradeoff." ], "avoid": [ "Empty jargon." ] }, "phrase_kit": { "uses": [], "avoid": [], "replacements": [] }, "jargon_policy": { "allow": [], "explain_with": [ "a tiny example" ] }, "formatting_directives": [ "Use short paragraphs." ], "do_dont": { "do": [ "Lead with value." ], "dont": [ "Invent facts." ], "never_does": [ "Hide uncertainty." ] }, "locale_and_dialect": "Natural American English.", "thinking_style": "Test conclusions against evidence.", "spoken_patterns": { "common_phrases": [], "starter_words": [], "transition_phrases": [] }, "rewriter_directives": [ "Address the listener as you." ], "adherence_checklist": [ "No invented specifics." ], "lexical_glossary": [], "example_paragraph": "Start with the decision your viewer needs to make. Then give them only the evidence that changes it.", "style_examples": [ "Start with the decision your viewer needs to make. Then build the explanation around the evidence that changes that decision." ] } }, "created_at": "2026-07-22T12:00:00Z", "updated_at": "2026-07-22T12:00:00Z" }, "meta": { "idempotent_replay": false } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ## Webhooks ### `GET /api/v1/webhooks` **Operation ID:** `listWebhooks` **Purpose:** List Webhooks. **Abilities:** `webhooks:read` **Response `200` example** ```json { "success": true, "data": [ { "id": 12, "name": "Production notifications", "url": "https://example.com/webhooks/subscribr", "events": [ "script.generated", "idea.created" ], "active": true, "success_rate": 98.5, "last_delivery": null } ] } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `POST /api/v1/webhooks` **Operation ID:** `createWebhook` **Purpose:** Create Webhook. **Abilities:** `webhooks:write` **Write safety:** idempotency `unsupported`; concurrency `unsupported`; retry `never`. **Request example** ```json { "name": "Partner hook", "url": "https://example.com/webhooks/subscribr", "events": [ "script.generated" ], "headers": { "X-Partner": "subscribr" }, "timeout": 30 } ``` **Response `201` example** ```json { "success": true, "data": { "id": 13, "name": "Partner hook", "url": "https://example.com/webhooks/subscribr", "events": [ "script.generated" ], "secret": "store-this-secret-once", "active": true, "timeout": 30 } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `GET /api/v1/webhooks/{webhook}` **Operation ID:** `getWebhook` **Purpose:** Get Webhook. **Abilities:** `webhooks:read` **Parameters** - `webhook` — path, required **Response `200` example** ```json { "success": true, "data": { "id": 12, "name": "Production notifications", "url": "https://example.com/webhooks/subscribr", "events": [ "script.generated", "idea.created" ], "active": true, "headers": null, "timeout": 30, "success_rate": 98.5, "deliveries": [ { "id": 901, "event_type": "script.generated", "status": "success", "response_code": 200 } ] } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `PUT /api/v1/webhooks/{webhook}` **Operation ID:** `updateWebhook` **Purpose:** Update Webhook. **Abilities:** `webhooks:write` **Write safety:** idempotency `unsupported`; concurrency `unsupported`; retry `never`. **Parameters** - `webhook` — path, required **Request example** ```json { "active": false, "headers": { "X-Partner": "updated" }, "timeout": 45 } ``` **Response `200` example** ```json { "success": true, "data": { "id": 12, "name": "Production notifications", "url": "https://example.com/webhooks/subscribr", "events": [ "script.generated" ], "active": false, "timeout": 30 } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `DELETE /api/v1/webhooks/{webhook}` **Operation ID:** `deleteWebhook` **Purpose:** Delete Webhook. **Abilities:** `webhooks:write` **Write safety:** idempotency `unsupported`; concurrency `unsupported`; retry `never`. **Parameters** - `webhook` — path, required **Response `200` example** ```json { "success": true, "message": "Webhook deleted successfully" } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500` ### `POST /api/v1/webhooks/{webhook}/test` **Operation ID:** `testWebhook` **Purpose:** Test Webhook. **Abilities:** `webhooks:write` **Write safety:** idempotency `unsupported`; concurrency `unsupported`; retry `never`. **Parameters** - `webhook` — path, required **Response `200` example** ```json { "success": true, "data": { "success": true, "status_code": 200, "response_body": "{\"received\":true}", "error": null } } ``` **Errors:** `400`, `401`, `403`, `404`, `422`, `429`, `500`