Ideas
/channels/{id}/ideas
POST /channels/{id}/ideasCreate a new video idea in the ideas system.
Request
JSON body with idea fields. No credits charged on create.
Request Body Fields
| Field | Type | Required | Description |
|---|---|---|---|
| title | string | Yes | Max 255 characters |
| topic | string | No | Max 5000 characters |
| angle | string | No | Max 1000 characters |
| suggested_length | integer | No | 200–20000 word target |
| suggested_template_id | integer | No | Must exist in templates table |
| thumbnail_concept | string | No | Max 1000 characters |
| notes | string | No | Max 2000 characters |
{
"title": "Why Apple's AI Changes Everything",
"topic": "Analysis of Apple Intelligence",
"angle": "Reveal the hidden implication that most reviews miss.",
"suggested_length": 1200,
"thumbnail_concept": "Split-screen before/after with bold headline"
}
Response (201)
{
"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
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
| success | boolean | Request success |
| data.id | integer | Idea ID |
| data.channel_id | integer | Channel ID |
| data.title | string | Idea title |
| data.topic | string|null | Topic |
| data.angle | string|null | Angle |
| data.suggested_length | integer|null | Target word count |
| data.status | string | Idea status |
| data.script_id | integer|null | Linked script when converted |
| data.source_type | string | user_added, ai_generated, from_video, … |
Error Responses
| Status | Error code | Description |
|---|---|---|
| 403 | You do not have access to this channel | No channel access |
| 404 | (not found) | Channel not found |
/channels/{id}/ideas
GET /channels/{id}/ideasList ideas for a channel with optional filters.
Request
No request body required.
Parameters
| Name | Type | Description |
|---|---|---|
| id | integer | Channel ID (path parameter) |
| status | string | Filter by status: new, considering, needs_script, rejected (deprecated banger is accepted as considering). Use scripted to return ideas with a non-null script_id (not a stored status value). |
| source_type | string | Filter by source (user_added, ai_generated, from_video, from_channel, outlier, chat_saved) |
| search | string | Search in title, topic, or angle |
| per_page | integer | 1-100, default 20 |
| page | integer | Page number (default 1) |
Response (200)
{
"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
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
| success | boolean | Request success |
| data[].id | integer | Idea ID |
| data[].channel_id | integer | Channel ID |
| data[].title | string | Idea title |
| data[].topic | string|null | Idea topic (nullable) |
| data[].status | string | Idea status |
| data[].angle | string|null | Angle |
| data[].suggested_length | integer|null | Target word count |
| data[].status | string | Idea status |
| data[].script_id | integer|null | Linked script ID |
| data[].source_type | string | Source type |
| pagination.current_page | integer | Current page |
| pagination.per_page | integer | Page size |
| pagination.total | integer | Total results |
| pagination.last_page | integer | Last page |
Error Responses
| Status | Error code | Description |
|---|---|---|
| 403 | You do not have access to this channel | No channel access |
/ideas/{id}
GET /ideas/{id}Get a single idea by ID.
Request
No request body required.
Parameters
| Name | Type | Description |
|---|---|---|
| id | integer | Idea ID (path parameter) |
Response (200)
{
"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
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
| success | boolean | Request success |
| data.id | integer | Idea ID |
| data.channel_id | integer | Channel ID |
| data.title | string | Idea title |
| data.topic | string|null | Topic |
| data.angle | string|null | Angle or hook |
| data.suggested_length | integer|null | Target word count |
| data.suggested_template_id | integer|null | Suggested template ID |
| data.status | string | new, considering, needs_script, rejected |
| data.script_id | integer|null | Linked script when converted |
| data.source_type | string | user_added, ai_generated, from_video, from_channel, outlier, chat_saved |
| data.thumbnail_concept | string|null | Thumbnail concept |
| data.outlier_score | number|null | Outlier score when set |
| data.notes | string|null | Internal notes |
Error Responses
| Status | Error code | Description |
|---|---|---|
| 403 | You do not have access to this idea | No channel access |
| 404 | (not found) | Idea not found |
/ideas/{id}/write
POST /ideas/{id}/writeConvert an idea into a canvas script (synchronous). Checks credits for the idea's target length; actual generation credits apply when you call Generate Script. Rate limit: 5 requests/minute (script).
Request
No request body. Idea ID is the `{id}` path parameter.
Parameters
| Name | Type | Description |
|---|---|---|
| id | integer | Idea ID (path) |
Response (201)
{
"success": true,
"data": {
"script_id": 789,
"script_number": 12,
"thread_id": 456,
"canvas_url": "https://subscribr.ai/chat/my-channel-thread/canvas/789"
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
| success | boolean | Request success |
| data.script_id | integer | Created or existing script ID |
| data.script_number | integer | Script number within channel |
| data.thread_id | integer | 201 only — chat thread ID |
| data.canvas_url | string | 201 only — browser canvas URL |
| data.status | string | 200 idempotent response only |
| message | string | 200 idempotent response only |
- Returns 201 when a new script is created.
- Returns 200 when the idea already has script_id (idempotent) — includes message and status, omits thread_id and canvas_url.
Error Responses
| Status | Error code | Description |
|---|---|---|
| 402 | insufficient_credits | Not enough credits for target length |
| 403 | subscription_paused | Team subscription paused |
| 403 | You do not have access to this idea | No channel access |
| 404 | (not found) | Idea not found |
/channels/{id}/ideas/generate
POST /channels/{id}/ideas/generateQueue AI generation of new ideas for a channel library. Async — poll List Channel Ideas; new rows use source_type ai_generated when ready.
Request
Optional count. Path id is your Subscribr channel ID.
Parameters
| Name | Type | Description |
|---|---|---|
| id | integer | Subscribr channel ID (path) |
Request Body Fields
| Field | Type | Required | Description |
|---|---|---|---|
| count | integer | No | 1–20 ideas. Default 10. |
{
"count": 10
}
Response (202)
{
"success": true,
"message": "Idea generation started.",
"data": {
"channel_id": 123,
"count": 10
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
| success | boolean | Request success |
| message | string | Status message |
| data.channel_id | integer | Channel ID |
| data.count | integer | Number of ideas to generate |
- Returns 202 immediately. There is no job ID — refresh ideas via GET /channels/{id}/ideas.
Error Responses
| Status | Error code | Description |
|---|---|---|
| 403 | You do not have access to this channel | No channel access |
| 404 | (not found) | Channel not found |
/channels/{id}/ideas/generate-from-video
POST /channels/{id}/ideas/generate-from-videoQueue ideas inspired by a long-form YouTube video. Provide video_url or video_id (one required). Shorts (< 3 min) are rejected.
Request
One of video_url or video_id is required.
Parameters
| Name | Type | Description |
|---|---|---|
| id | integer | Subscribr channel ID (path) |
Request Body Fields
| Field | Type | Required | Description |
|---|---|---|---|
| video_url | string | No | YouTube watch URL. Required if video_id omitted. Max 500. |
| video_id | string | No | 11-character video ID. Required if video_url omitted. |
| count | integer | No | 1–20. Default 10. |
{
"video_url": "https://youtube.com/watch?v=dQw4w9WgXcQ",
"count": 10
}
Response (202)
{
"success": true,
"message": "Idea generation from video started.",
"data": {
"channel_id": 123,
"count": 10
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
| success | boolean | Request success |
| message | string | Status message |
| data.channel_id | integer | Channel ID |
| data.count | integer | Number of ideas to generate |
- Returns 202. Poll List Channel Ideas; completed ideas use source_type from_video.
- Video is fetched via Intel lookup before generation is queued.
Error Responses
| Status | Error code | Description |
|---|---|---|
| 403 | You do not have access to this channel | No channel access |
| 422 | Invalid YouTube video ID or URL. | Could not parse video ID |
| 422 | YouTube Shorts are not supported | Video under 3 minutes |
| 400 | Could not fetch video | Intel lookup failed |
| 404 | Video fetched but not found in database | Transient indexing issue — retry |
/channels/{id}/ideas/generate-from-channel
POST /channels/{id}/ideas/generate-from-channelQueue ideas inspired by top videos from another YouTube channel. The source channel must already exist in Subscribr (Intel lookup, competitor tracking, etc.). Async — poll List Channel Ideas.
Request
One of channel_handle or channel_id is required.
Parameters
| Name | Type | Description |
|---|---|---|
| id | integer | Subscribr channel receiving ideas (path) |
Request Body Fields
| Field | Type | Required | Description |
|---|---|---|---|
| channel_handle | string | No | e.g. @mkbhd. Required if channel_id omitted. Max 200. |
| channel_id | string | No | YouTube UC channel ID. Required if channel_handle omitted. Max 50. |
| count | integer | No | 1–20. Default 10. |
{
"channel_handle": "@mkbhd",
"count": 10
}
Response (202)
{
"success": true,
"message": "Idea generation from channel started.",
"data": {
"channel_id": 123,
"source_channel_title": "Marques Brownlee",
"count": 10
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
| success | boolean | Request success |
| message | string | Status message |
| data.channel_id | integer | Your channel ID receiving the ideas |
| data.source_channel_title | string | Title of the YouTube channel used as inspiration |
| data.count | integer | Number of ideas to generate |
- Provide channel_handle or channel_id (YouTube UC id), not your Subscribr channel id.
- Completed ideas use source_type from_channel.
Error Responses
| Status | Error code | Description |
|---|---|---|
| 403 | You do not have access to this channel | No access to destination channel |
| 404 | YouTube channel not found | Source channel not indexed in Subscribr |
/ideas/{id}/change-topic
POST /ideas/{id}/change-topicQueue async rewrite of an idea's title, angle, and thumbnail concept for a new topic while keeping the same hook structure. Poll Get Idea Details for updates.
Request
JSON body with new topic direction.
Parameters
| Name | Type | Description |
|---|---|---|
| id | integer | Idea ID (path) |
Request Body Fields
| Field | Type | Required | Description |
|---|---|---|---|
| topic | string | Yes | New topic direction. 3–5000 characters. |
{
"topic": "Instead of productivity apps, apply this to morning routines"
}
Response (202)
{
"success": true,
"message": "Topic change started.",
"data": {
"idea_id": 456
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
| success | boolean | Request success |
| message | string | Status message |
| data.idea_id | integer | ID of the idea being updated |
Error Responses
| Status | Error code | Description |
|---|---|---|
| 403 | You do not have access to this idea | No channel access |
| 404 | (not found) | Idea not found |