Subscribr API
Thumbnails
/team/thumbnails/usage
GET /team/thumbnails/usageGet current thumbnail generation quota and usage for your team. Returns up to three quota pools: the free pool (included with every plan), an optional add-on pool (monthly subscription), and an optional pack pool (one-time purchased credits). The total_remaining field provides the combined remaining generations across all pools.
Rate limit: 60 requests per minute
Request
No request body required.
Response (200)
{
"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
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
| success | boolean | Request success |
| data.eligible | boolean | Whether the team is eligible for thumbnail generation (requires active subscription) |
| data.free_pool | object | Free pool included with every plan |
| data.free_pool.limit | integer | Monthly free generation limit |
| data.free_pool.used | integer | Completed generations this period |
| data.free_pool.reserved | integer | In-progress generations (counted against remaining until completed or released) |
| data.free_pool.remaining | integer | Available generations (limit minus used minus reserved) |
| data.free_pool.next_reset | string|null | Pool reset date (Y-m-d format) |
| data.addon_pool | object|null | Monthly add-on subscription pool (null if not subscribed). Same fields as free_pool. |
| data.pack_pool | object|null | One-time purchased credit pack (null if none purchased). Same fields as free_pool. next_reset is always null — pack credits do not expire. |
| data.total_remaining | integer | Combined remaining across all active pools |
/channels/{id}/thumbnails/generations
POST /channels/{id}/thumbnails/generationsCreate an asynchronous thumbnail generation for a channel. Three main modes: (1) **Idea-based** — provide an idea_id to generate a final 2K thumbnail from an existing idea. (2) **Brainstorm** — provide a prompt (no idea_id) to generate concept sketches at 1K resolution. Brainstorm results are stored as concept variations on a new idea; to produce final 2K thumbnails, call this endpoint again with the returned idea_id. (3) **Clone** — provide a clone_strategy and reference_image_url to generate thumbnails that match an existing thumbnail's style. The generation runs in the background; poll the returned run_id for status or use callback_url for async notification.
Rate limit: 12 requests per minute
Request
JSON body. Path id is your Subscribr channel ID. Requires active subscription (403 if ineligible).
Parameters
| Name | Type | Description |
|---|---|---|
| id | integer | Subscribr channel ID (path). |
Request Body Fields
| Field | Type | Required | Description |
|---|---|---|---|
| idea_id | integer | No | Idea-based or improvement mode. Must belong to channel. |
| prompt | string | No | Required for brainstorm/clone when idea_id omitted. Max 2000. |
| topic | string | No | Brainstorm context. Max 1000. |
| num_variations | integer | No | 1–8. Default 1 with idea_id, 4 without. Each variation reserves one quota unit when idea_id set. |
| callback_url | string | No | HTTPS callback (not team webhooks). Max 2048. |
| callback_secret | string | No | Signs callback body via X-Subscribr-Signature. Max 255. |
| improvement_mode | boolean | No | Requires idea_id, feedback, reference_variation_url. |
| feedback | string | No | Required when improvement_mode=true. Max 5000. |
| reference_variation_url | string | No | HTTPS URL. Required when improvement_mode=true. |
| clone_strategy | string | No | direct_reference or style_analysis |
| reference_image_url | string | No | HTTPS reference image. Required when clone_strategy set. |
{
"idea_id": 42,
"num_variations": 3,
"callback_url": "https://partner.example.com/subscribr/thumbnail-callback",
"callback_secret": "whsec_thumbnail_partner_secret"
}
Response (202)
{
"success": true,
"data": {
"run_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
"run_ids": [
"9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d"
],
"status": "queued"
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
| data.run_id | string | Primary generation run ID (UUID). Use this to poll status via the Get Generation Status endpoint. |
| data.run_ids | array | All run IDs for this request. When num_variations > 1 with an idea_id, each variation gets its own run ID that can be polled individually. |
| data.status | string | Initial status (always "queued") |
| data.idea_id | integer | Returned only for clone modes — the auto-created idea ID |
- Clone with style_analysis: When clone_strategy=style_analysis, the response has a different shape: { idea_id, status: "style_analysis_pending", message }. Style analysis runs asynchronously before thumbnail generation. Use a callback_url to be notified when analysis completes, then call this endpoint again with the returned idea_id to generate the final thumbnail.
- Quota consumption: Quota is reserved per generation run. When num_variations > 1 with an idea_id, each variation gets its own run_id and consumes one quota unit. Brainstorm mode (no idea_id) reserves one unit for the batch. Reserved quota is released if a run fails.
Error Responses
| Status | Error code | Description |
|---|---|---|
| 403 | not eligible for thumbnail generation | No active subscription |
| 404 | Idea not found in this channel | Invalid idea_id |
| 429 | (quota) | Insufficient thumbnail quota |
/channels/{id}/thumbnails/generations/{runId}
GET /channels/{id}/thumbnails/generations/{runId}Get the current status and results of a thumbnail generation. When the status is "completed", the output_urls array contains URLs to the generated thumbnail images. Poll this endpoint after creating a generation to track progress.
Rate limit: 120 requests per minute
Request
No request body required.
Parameters
| Name | Type | Description |
|---|---|---|
| id | integer | Channel ID (path parameter). |
| runId | string | Generation run ID returned from the Create endpoint (path parameter). |
Response (200)
{
"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"
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
| data.run_id | string | Generation run identifier (UUID) |
| data.status | string | Status: queued (processing), completed (output ready), or failed |
| data.idea_id | integer|null | Linked idea ID (present when using idea-based or clone modes) |
| data.output_urls | array | Generated thumbnail image URLs (populated when status is "completed", empty otherwise) |
| data.output_urls[] | string | URL to a generated thumbnail image |
| data.created_at | string | ISO 8601 creation timestamp |
| data.updated_at | string | ISO 8601 last update timestamp (indicates when status last changed) |
/channels/{id}/thumbnails/generations
GET /channels/{id}/thumbnails/generationsList past thumbnail generation runs for a channel. Returns a paginated list (15 per page) ordered by most recent first. Optionally filter by source_type to narrow results to a specific generation mode.
Rate limit: 120 requests per minute
Request
Optional query parameters to filter and paginate results.
Parameters
| Name | Type | Description |
|---|---|---|
| id | integer | Channel ID (path parameter). |
| source_type | string | Filter by ThumbnailUsageEvent source_type: api_generate (idea-based and brainstorm API runs), idea_improve, thumbnail_clone |
| page | integer | Page number (default 1). |
Response (200)
{
"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
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
| data[] | array | List of generation run objects |
| data[].run_id | string | Run identifier (UUID) — use with the Get Generation Status endpoint |
| data[].status | string | Status: queued, completed, or failed |
| data[].source_type | string | api_generate, idea_improve, or thumbnail_clone |
| data[].idea_id | integer|null | Linked idea ID (null for brainstorm runs without a pre-existing idea) |
| data[].output_urls | array | Generated thumbnail URLs (empty for queued/failed runs) |
| data[].created_at | string | ISO 8601 creation timestamp |
| meta.current_page | integer | Current page number |
| meta.last_page | integer | Total number of pages |
| meta.per_page | integer | Items per page (15) |
| meta.total | integer | Total matching generation runs |
/channels/{id}/thumbnails/board
GET /channels/{id}/thumbnails/boardRead the channel's Thumbnail Studio board: a spatial canvas of image tiles (imported thumbnails, uploads, AI variations, exports) and editable text overlays. Each channel has one board. Returns every item with its position, status, and image URL. Items with status "generating" are still rendering — poll this endpoint until they turn "ready". The studio_url field links to the board in the Subscribr app.
Rate limit: 120 requests per minute
Request
No request body required.
Parameters
| Name | Type | Description |
|---|---|---|
| id | integer | Subscribr channel ID (path). |
Response (200)
{
"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"
}
]
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
| data.board_id | integer|null | Board ID (null until the first write command creates the board) |
| data.studio_url | string | Link to the board in Thumbnail Studio |
| data.credits_remaining | integer | Combined remaining thumbnail credits across all pools |
| data.items[] | array | Board items ordered by z-index |
| data.items[].type | string | image, text, shape, or frame |
| data.items[].status | string | ready, generating, or failed |
| data.items[].url | string | Image URL (image items only, once ready) |
| data.items[].content | string | Headline text (text items only) |
| data.items[].usage | string | Reference tag: creator_face, style, product, background, or screenshot |
| data.items[].assigned_script_id | integer|null | Set when this image is the current thumbnail of a script (project) |
| data.items[].assigned_script_title | string|null | Title of the script this image is assigned to |
/channels/{id}/thumbnails/board/images
POST /channels/{id}/thumbnails/board/imagesImport reference images onto the board as a labeled frame. Sources my_recent, my_top_viewed, and my_top_outlier pull the channel's own YouTube thumbnails; source urls adds up to 12 external image URLs, optionally tagged with a usage such as creator_face (exact likeness) or style (visual style to copy). Added images can then be passed as reference_item_ids to Create Board Generation.
Rate limit: 12 requests per minute
Request
JSON body. Boards hold at most 500 images; requests past the cap return 422.
Parameters
| Name | Type | Description |
|---|---|---|
| id | integer | Subscribr channel ID (path). |
Request Body Fields
| Field | Type | Required | Description |
|---|---|---|---|
| source | string | Yes | my_recent, my_top_viewed, my_top_outlier, or urls. |
| urls | array | No | Required when source is urls. Up to 12 image URLs. |
| usage | string | No | Tag for URL imports: creator_face, style, product, background, or screenshot. |
| label | string | No | Frame label. Max 80. Default "API imports". |
Response (200)
{
"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://example.com/reference.png",
"usage": "style",
"source": "upload"
}
]
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
| data.items[] | array | The new frame plus one image item per imported thumbnail |
| data.items[].id | integer | Item ID — use as a reference_item_id when generating |
/channels/{id}/thumbnails/board/generations
POST /channels/{id}/thumbnails/board/generationsRender new thumbnail variations onto the board from a prompt plus selected reference items. Spends 1 thumbnail credit per variation. Rendering is asynchronous (typically 10-60 seconds per image): the response returns placeholder items with status "generating" — poll Get Thumbnail Board until they turn "ready". Failed renders release their credit automatically. Text is kept out of the generated image by default; words in the prompt become an editable text overlay instead. Set allow_text to true to bake text into the image.
Rate limit: 12 requests per minute
Request
JSON body. Requires an active subscription (403 if ineligible) and available thumbnail credits (429 when exhausted).
Parameters
| Name | Type | Description |
|---|---|---|
| id | integer | Subscribr channel ID (path). |
Request Body Fields
| Field | Type | Required | Description |
|---|---|---|---|
| prompt | string | Yes | What to generate. 3-2000 characters. |
| reference_item_ids | array | No | Up to 6 ready image item IDs to use as visual references. |
| variations | integer | No | 1-8. Default 2. Each variation spends one credit. |
| allow_text | boolean | No | Bake text into the image. Default false (text becomes an editable overlay). |
Response (200)
{
"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\"."
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
| data.credits_spent | integer | Credits reserved for this request |
| data.items[] | array | Placeholder image items (plus an editable text overlay when the prompt asked for words and allow_text is false) |
| data.items[].status | string | "generating" until the render completes |
/channels/{id}/thumbnails/board/edits
POST /channels/{id}/thumbnails/board/editsChange one ready board image with a plain-language instruction such as "remove the text" or "make the sky stormy". Spends 1 thumbnail credit. Non-destructive: the edit arrives as a new item beside the original, which is never altered, so you can compare takes and keep the one you want. Pass an optional region to confine the change to a rectangle of the image — pixels outside it are guaranteed identical to the original, because Subscribr composites the model output back over the source rather than trusting the model to stay inside the lines. Rendering is asynchronous (typically 10-60 seconds): poll Get Thumbnail Board until the new item turns "ready". A failed edit releases its credit automatically.
Rate limit: 12 requests per minute
Request
JSON body. Requires an active subscription (403 if ineligible) and an available thumbnail credit (429 when exhausted).
Parameters
| Name | Type | Description |
|---|---|---|
| id | integer | Subscribr channel ID (path). |
Request Body Fields
| Field | Type | Required | Description |
|---|---|---|---|
| item_id | integer | Yes | A ready image item on this board to edit. |
| instruction | string | Yes | One change to make. 3-2000 characters. |
| region | object | No | Confine the edit to a rectangle: x, y, width, height as fractions of the image (0-1). Regions under 2% in either dimension are ignored. |
Response (200)
{
"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\"."
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
| data.credits_spent | integer | Always 1 for an edit |
| data.items[] | array | The new placeholder item for the edit; the source item is untouched |
| data.items[].status | string | "generating" until the edit completes |
/channels/{id}/thumbnails/board/text
POST /channels/{id}/thumbnails/board/textAdd or update an editable headline overlay. Overlay text stays out of the generated image on purpose so it can be edited and swapped freely. Place a new overlay over an image with over_item_id, or pass item_id to update an existing overlay. Styling defaults come from the channel's analyzed thumbnail identity. Use Export Board Image to flatten overlays into a final PNG.
Rate limit: 12 requests per minute
Request
JSON body. content is required when creating a new overlay.
Parameters
| Name | Type | Description |
|---|---|---|
| id | integer | Subscribr channel ID (path). |
Request Body Fields
| Field | Type | Required | Description |
|---|---|---|---|
| content | string | No | Headline text. Max 200. Required without item_id. |
| item_id | integer | No | Existing text item to update. |
| over_item_id | integer | No | Image item to place a new overlay over. |
| x | integer | No | Board X position. |
| y | integer | No | Board Y position. |
| font | string | No | impact, anton, bebas, archivo, montserrat, oswald, bangers, luckiest, poppins, or system. |
| size | integer | No | Font size, 16-240. |
| fill | string | No | Text color as #RRGGBB. |
| stroke | string | No | Outline color as #RRGGBB. |
| stroke_width | integer | No | Outline width, 0-40. |
| background | string | No | Highlight box color as #RRGGBB, or null for none. |
| align | string | No | left, center, or right. |
Response (200)
{
"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"
}
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
| data.item | object | The text overlay item |
/channels/{id}/thumbnails/board/export
POST /channels/{id}/thumbnails/board/exportFlatten one ready image with every text overlay that overlaps it into a final 1280x720 PNG. Returns the stored URL and adds the export back onto the board as a new item. This is how an agent produces the finished, downloadable thumbnail.
Rate limit: 12 requests per minute
Request
JSON body.
Parameters
| Name | Type | Description |
|---|---|---|
| id | integer | Subscribr channel ID (path). |
Request Body Fields
| Field | Type | Required | Description |
|---|---|---|---|
| item_id | integer | Yes | A ready image item on the board. |
Response (200)
{
"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
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
| data.url | string | URL of the flattened 1280x720 PNG |
| data.overlays_flattened | integer | Number of text overlays baked into the export |
/channels/{id}/thumbnails/board/assign-to-script
POST /channels/{id}/thumbnails/board/assign-to-scriptMake a ready board image the thumbnail of a project (script) on this channel. Uses the same exclusive winner semantics as selecting a thumbnail on the Kanban board: the image is stored as a script attachment, marked as the thumbnail winner, and shown on the project card and detail view. The board item is stamped with assigned_script_id and assigned_script_title so later board reads show which image belongs to which project.
Rate limit: 12 requests per minute
Request
JSON body. The script must belong to the channel.
Parameters
| Name | Type | Description |
|---|---|---|
| id | integer | Subscribr channel ID (path). |
Request Body Fields
| Field | Type | Required | Description |
|---|---|---|---|
| item_id | integer | Yes | A ready image item on the board. |
| script_id | integer | Yes | The script (project) to receive the thumbnail. |
Response (200)
{
"success": true,
"data": {
"script_id": 88,
"attachment_id": 402,
"thumbnail_url": "https://subscribr.ai/storage/kanban-attachments/402.png"
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
| data.attachment_id | integer | The script attachment holding the stored copy |
| data.thumbnail_url | string | URL of the assigned thumbnail |