Channels
/channels
GET /channelsList channels the authenticated user can access on the current team. Results are filtered in-memory then paginated.
Request
No request body required.
Parameters
| Name | Type | Description |
|---|---|---|
| search | string | Search by channel title or handle. |
| per_page | integer | 1-100, default 20. |
| page | integer | Page number (default 1). |
Response (200)
{
"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
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
| success | boolean | Request success |
| data[].id | integer | Subscribr channel ID |
| data[].yt_handle | string|null | Stored YouTube handle |
| data[].details.title | string|null | Linked YouTube channel title |
| data[].details.channel_id | string|null | YouTube channel ID (UC…) |
| data[].details.subscriber_count | integer|null | Subscriber count when linked |
| data[].scripts_count | integer | Scripts on this channel |
| pagination.current_page | integer | Current page |
| pagination.per_page | integer | Page size |
| pagination.total | integer | Total accessible channels |
| pagination.last_page | integer | Last page number |
Error Responses
| Status | Error code | Description |
|---|---|---|
| 403 | Token does not have channels:read permission | Missing channels:read ability |
/channels/{id}
GET /channels/{id}Get detailed information about a specific channel including settings, default voice, and script counts.
Request
No request body required.
Parameters
| Name | Type | Description |
|---|---|---|
| id | integer | Subscribr channel ID. Unknown ID → 404. No access → 403. |
Response (200)
{
"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
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
| success | boolean | Request success |
| data.id | integer | Subscribr channel ID |
| data.yt_handle | string|null | Stored handle |
| data.details | object | YouTube metadata (title, custom_url, channel_id, counts, thumbnails, …) |
| data.settings | object | setting_name → setting_value map |
| data.voice | object|null | Default voice: id, name, instructions, voice |
| data.scripts_count | integer | All scripts |
| data.scripts_idea_count | integer | Scripts in idea status |
| data.scripts_active_count | integer | Scripts in active status |
Error Responses
| Status | Error code | Description |
|---|---|---|
| 403 | You do not have access to this channel | User lacks channel access |
| 404 | (not found) | Channel ID does not exist |
/channels/{id}/templates
GET /channels/{id}/templatesList script templates for a channel (system + custom). If none exist, default system templates are provisioned on first request.
Request
No request body required.
Parameters
| Name | Type | Description |
|---|---|---|
| id | integer | Channel ID (path parameter). |
Response (200)
{
"success": true,
"data": {
"default_template_id": 22,
"templates": [
{
"id": 22,
"name": "Base Script",
"category": "base",
"description": "Standard outline",
"is_active": true,
"is_system": true
}
]
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
| success | boolean | Request success |
| data.default_template_id | integer|null | Active template ID or null |
| data.templates | array | Template objects |
| templates[].id | integer | Template ID. |
| templates[].name | string | Template name. |
| templates[].category | string | Template category. |
| templates[].description | string | Short description. |
| templates[].is_active | boolean | Whether this is the active template. |
| templates[].is_system | boolean | System template flag. |
- default_template_id may be null when no template is marked active.
/channels/{id}/voices
GET /channels/{id}/voicesList available voices for channel and the default voice.
Request
No request body required.
Parameters
| Name | Type | Description |
|---|---|---|
| id | integer | Channel ID (path parameter). |
Response (200)
{
"success": true,
"data": {
"default_voice_id": 77,
"voices": [
{
"id": 77,
"name": "Default Voice",
"instructions": "Voice instructions",
"voice": "neutral"
}
]
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
| success | boolean | Request success |
| data.default_voice_id | integer|null | Default voice ID or null |
| data.voices | array | Voice objects |
| voices[].id | integer | Voice ID. |
| voices[].name | string | Voice name. |
| voices[].instructions | string | Voice guidelines. |
| voices[].voice | string | Voice identifier. |
/channels/{id}/competitors
GET/POST/DELETE /channels/{id}/competitorsList, add, delete competitors. GET: returns competitors array. POST: request with identifier. DELETE: no body.
Request
GET/DELETE: no body. POST: JSON with identifier.
Parameters
| Name | Type | Description |
|---|---|---|
| id | integer | Subscribr channel ID (path) |
| competitor | string | DELETE only — YouTube channel ID (path) |
Request Body Fields
| Field | Type | Required | Description |
|---|---|---|---|
| identifier | string | Yes | POST only. YouTube handle, channel ID, or URL. Max 255 chars. |
{
"identifier": "https://www.youtube.com/@competitor"
}
Response (GET) (200)
{
"success": true,
"data": [
{
"channel_id": "UC123...",
"title": "Competitor Channel",
"custom_url": "competitor",
"custom_url_with_at": "@competitor",
"youtube_url": "https://youtube.com/@competitor",
"thumbnails": {
"default": {
"url": "https://i.ytimg.com/..."
}
},
"subscriber_count": 500000,
"video_count": 300,
"view_count": 12000000
}
]
}
Response (POST) (201)
{
"success": true,
"data": {
"channel_id": 123,
"competitor": {
"channel_id": "UC123...",
"title": "Competitor Channel",
"custom_url": "competitor",
"custom_url_with_at": "@competitor",
"youtube_url": "https://youtube.com/@competitor"
}
}
}
Response (DELETE) (200)
{
"success": true,
"message": "Competitor removed."
}
Response Fields
| Field | Type | Description |
|---|---|---|
| channel_id | string | YouTube channel ID. |
| title | string | Channel title. |
| custom_url | string | Handle without @. |
| custom_url_with_at | string | Handle with @. |
| youtube_url | string | Full YouTube URL. |
| thumbnails | object | Thumbnail images object. |
| subscriber_count | integer | YouTube subscriber count. |
| video_count | integer | Total video count. |
| view_count | integer | Total view count. |
- GET requires channels:read. POST and DELETE require scripts:write.
- DELETE path parameter competitor is the YouTube channel ID (UC…), not the Subscribr channel id.