# Thumbnails

Generate, edit, and analyze YouTube thumbnails, including channel-style composition, faces, and presets.

### `POST /api/thumbnails`

Generate a YouTube thumbnail from a title and one or more reference thumbnails. The reference is vision-analysed and its design grammar is folded into an engineered prompt for your new title, then rendered. Returns a `task_id` immediately — poll `/api/thumbnails/status/{task_id}` for the image URLs. Costs 1 credit (or a flat 3 with `fast: true`), deducted upfront and refunded automatically if generation fails.

Your API key must carry the `generations` scope.

**Request Body (JSON)**

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| prompt | string | Required | — | The new video title to design the thumbnail for. |
| reference_urls | string[] | Required | — | One or more references — each a YouTube video URL, a bare 11-char video id, or a direct image URL. The first is used as the primary design reference. At least one is required. |
| model | string | Optional | nano-banana-pro | Image model. One of `nano-banana-pro`, `nano-banana-2`, `seedream-5.0-lite`, `seedream-4.5-edit`, `gpt-image-2.5`. |
| aspect_ratio | string | Optional | 16:9 | Output aspect ratio (e.g. `16:9`, `9:16`, `1:1`). |
| resolution | string | Optional | 2K | Output resolution (`1K`, `2K`, or `4K`). |
| reference_titles | object | Optional | — | Map of `reference_url` → the reference video's original title, so the prompt knows why that thumbnail worked for that title. |
| find_outliers_first | boolean | Optional | false | Auto-fetch up to 3 topically-similar outlier thumbnails to use as extra references (topic taken from `outlier_topic` or `prompt`). |
| custom_instructions | string | Optional | — | Extra art-direction appended to the engineered prompt with highest salience. |
| fast | boolean | Optional | false | Fast mode — sub-30s renders on a dedicated queue with no fallback provider. Flat **3 credits** per generation regardless of model. |

**Example Request**

```
curl -X POST "https://api.algrow.online/api/thumbnails" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"prompt": "How I Built a $1M App in 30 Days", "reference_urls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"], "model": "nano-banana-pro"}'
```

**Response 200 200**

```
{
  "success": true,
  "task_id": "a1b2c3d4-...",
  "state": "pending",
  "model": "nano-banana-pro",
  "credits_used": 1,
  "message": "Thumbnail generation queued. Poll /api/thumbnails/status/{task_id} for progress."
}
```

200 Queued 400 Validation error 401 Auth failed 402 No credits 429 Too busy 502 Submit failed

### `POST /api/thumbnails/channel-style`

Generate a thumbnail in a specific channel's own design style. We resolve the channel, pull its top longform thumbnails, analyse them, pick the one whose design best fits your title, and recreate that treatment for your title (the channel's subjects never carry over — only its design language). Returns a `task_id` immediately — poll `/api/thumbnails/status/{task_id}` for the image. Costs 1 credit (or a flat 3 with `fast: true`), deducted upfront and refunded automatically on failure.

Requires the `generations` scope. The compose step runs inline and can take 30–90 seconds before the `task_id` is returned.

**Request Body (JSON)**

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| channel | string | Required | — | The channel to borrow the style from — a UC channel id, `@handle`, or channel URL. |
| title | string | Required | — | The new video title to design the thumbnail for. |
| model | string | Optional | nano-banana-pro | Image model. One of `nano-banana-pro`, `nano-banana-2`, `seedream-5.0-lite`, `seedream-4.5-edit`, `gpt-image-2.5`. |
| custom_instructions | string | Optional | — | Extra art-direction applied on top of the matched channel style. |
| fast | boolean | Optional | false | Fast mode — sub-30s renders on a dedicated queue with no fallback provider. Flat **3 credits** per generation regardless of model. |

**Example Request**

```
curl -X POST "https://api.algrow.online/api/thumbnails/channel-style" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"channel": "@MrBeast", "title": "I Survived 50 Hours in the Arctic"}'
```

**Response 200 200**

```
{
  "success": true,
  "task_id": "a1b2c3d4-...",
  "state": "pending",
  "model": "nano-banana-pro",
  "credits_used": 1,
  "matched_thumb_url": "https://i.ytimg.com/vi/.../maxresdefault.jpg",
  "match_reason": "..."
}
```

200 Queued 400 Validation error 401 Auth failed 402 No credits 502 Compose/submit failed

### `POST /api/thumbnails/edit`

Edit an already-generated thumbnail with a plain-English instruction. The image goes back to the model as the canvas and only the requested change is applied — optional `reference_urls` are source material for the change ("insert THIS product"). Returns a `task_id` immediately — poll `/api/thumbnails/status/{task_id}` for the edited image. Costs 1 credit (or a flat 3 with `fast: true`), deducted upfront and refunded automatically on failure. Note: `gpt-image-2.5` requests are served by `nano-banana-pro` for edits.

Requires the `generations` scope.

**Request Body (JSON)**

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| base_image_url | string | Required | — | Direct http(s) URL of the thumbnail to edit — typically an image URL returned by a previous generation. |
| instruction | string | Required | — | The change to make, in plain English (e.g. "make the text yellow"). Max 2000 characters. |
| reference_urls | string[] | Optional | — | Extra images used as source material for the change (e.g. the product to insert). Each a YouTube video URL, a bare 11-char video id, or a direct image URL. |
| model | string | Optional | nano-banana-pro | Image model. One of `nano-banana-pro`, `nano-banana-2`, `seedream-5.0-lite`, `seedream-4.5-edit`, `gpt-image-2.5`. `gpt-image-2.5` is auto-served by `nano-banana-pro` for edits. |
| aspect_ratio | string | Optional | 16:9 | Output aspect ratio (e.g. `16:9`, `9:16`, `1:1`). |
| resolution | string | Optional | 2K | Output resolution (`1K`, `2K`, or `4K`). |
| fast | boolean | Optional | false | Fast mode — sub-30s renders on a dedicated queue with no fallback provider. Flat **3 credits** per edit regardless of model. |

**Example Request**

```
curl -X POST "https://api.algrow.online/api/thumbnails/edit" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"base_image_url": "https://cdn.algrow.online/thumbnails/a1b2c3d4.png", "instruction": "make the text yellow"}'
```

**Response 200 200**

```
{
  "success": true,
  "task_id": "a1b2c3d4-...",
  "state": "pending",
  "model": "nano-banana-pro",
  "credits_used": 1,
  "message": "Thumbnail edit queued. Poll /api/thumbnails/status/{task_id} for progress."
}
```

200 Queued 400 Validation error 401 Auth failed 402 No credits 502 Submit failed

### `GET /api/thumbnails/models`

List the thumbnail models available to your account, their per-generation credit cost, and the fast-mode flat rate. Free — use this for capability discovery instead of hardcoding model names.

**Example Request**

```
curl "https://api.algrow.online/api/thumbnails/models" \
-H "Authorization: Bearer YOUR_API_KEY"
```

**Response 200 200**

```
{
  "success": true,
  "default_model": "nano-banana-pro",
  "models": [
    {"model": "nano-banana-pro", "label": "Nano Banana Pro", "requires_reference": false, "credit_cost": 1},
    {"model": "seedream-4.5-edit", "label": "Seedream 4.5 Edit", "requires_reference": true, "credit_cost": 1}
  ],
  "fast_mode": {"param": "fast", "credit_cost": 3}
}
```

200 OK 401 Auth failed

### `GET /api/thumbnails/status/:task_id`

Retrieve the status and result of a thumbnail generation. Poll every 2–3 seconds until `state` is `success` or `fail`. Typical generation time is 30–90 seconds. On a failure, the credits charged at submit are refunded automatically.

**Path Parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| task_id | string | Required | The `task_id` returned from `POST /api/thumbnails`. |

**Example Request**

```
curl "https://api.algrow.online/api/thumbnails/status/a1b2c3d4-..." \
-H "Authorization: Bearer YOUR_API_KEY"
```

**Response — Success**

```
{
  "success": true,
  "task_id": "a1b2c3d4-...",
  "state": "success",
  "images": ["https://...thumbnail.png"],
  "cost_time_ms": 42137
}
```

**Response — Failed**

```
{
  "success": true,
  "task_id": "a1b2c3d4-...",
  "state": "fail",
  "error": "Generation failed"
}
```

**Response Fields**

| Field | Type | Description |
| --- | --- | --- |
| state | string | Generation state: a pending value (`processing`/`waiting`/`queuing`/`generating`), `success`, or `fail`. Prompt engineering runs for 1–3 minutes before the render is submitted, so expect `processing` for a while; keep polling the id you were given until it is terminal. |
| images | string[] | Generated thumbnail URLs (only when `state=success`). |
| error | string | Error description (only when `state=fail`). |

200 Success 401 Auth failed 404 Not found

### `POST /api/thumbnails/outliers`

Find topically-similar, high-performing reference thumbnails for a topic. Free (a database lookup, no credits). Pass the returned `thumbnail_url` values straight into `POST /api/thumbnails` as `reference_urls` to build a thumbnail in a proven style.

Requires the `generations` scope.

**Request Body (JSON)**

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| topic | string | Required | — | The topic/niche to find outlier thumbnails for (e.g. `minecraft survival`). |
| content_type | string | Optional | longform | `longform` or `shorts`. |
| limit | integer | Optional | 12 | Number of results to return. |
| min_outlier_score | number | Optional | 2.0 | Minimum outlier score (how far a video outperforms its channel baseline). |
| page | integer | Optional | 1 | Page number for pagination. |

**Example Request**

```
curl -X POST "https://api.algrow.online/api/thumbnails/outliers" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"topic": "minecraft survival", "limit": 12}'
```

200 Success 400 Validation error 401 Auth failed

### `POST /api/thumbnails/channel-videos`

Page through a channel's LONGFORM upload catalogue (shorts excluded) — newest first, 50 per page, each video with its thumbnail, title and view count, plus the channel's recent-median baseline (`median_views`) for outlier scoring (`view_count / median_views`). Free (1–2 YouTube quota units per page, no credits). Pick a `thumbnail_url` and pass it to `POST /api/thumbnails` as a reference.

Requires the `generations` scope.

**Request Body (JSON)**

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| channel | string | Required | — | Channel `@handle`, URL, or `UC` id. |
| page_token | string | Optional | — | `next_page_token` from the previous response. |
| playlist_id | string | Optional | — | `playlist_id` from the previous response — page tokens are playlist-specific. |

**Example Request**

```
curl -X POST "https://api.algrow.online/api/thumbnails/channel-videos" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"channel": "@MrBeast"}'
```

200 Success 400 Validation error 401 Auth failed

### `GET /api/thumbnails/saved-channels`

List your saved channel styles (identity only — name, handle, avatar, channel id). The catalogue itself is always fetched live via `POST /api/thumbnails/channel-videos`. Free.

Requires the `generations` scope.

**Example Request**

```
curl "https://api.algrow.online/api/thumbnails/saved-channels" \
-H "Authorization: Bearer YOUR_API_KEY"
```

200 Success 400 Validation error 401 Auth failed

### `POST /api/thumbnails/saved-channels`

Save a channel style for one-click reuse. Snapshots the channel's name, handle and avatar (1 YouTube quota unit). Upserts by channel. Free.

Requires the `generations` scope.

**Request Body (JSON)**

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| channel | string | Required | — | Channel `@handle`, URL, or `UC` id. |

**Example Request**

```
curl -X POST "https://api.algrow.online/api/thumbnails/saved-channels" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"channel": "@MrBeast"}'
```

200 Success 400 Validation error 401 Auth failed

### `DELETE /api/thumbnails/saved-channels/{channel_id}`

Remove a channel from your saved styles. Free.

Requires the `generations` scope.

**Example Request**

```
curl -X DELETE "https://api.algrow.online/api/thumbnails/saved-channels/UCX6OQ3DkcsbYNE6H8uQQuVA" \
-H "Authorization: Bearer YOUR_API_KEY"
```

200 Success 400 Validation error 401 Auth failed

### `GET /api/thumbnails/instruction-presets`

List your saved custom-instruction presets. Apply one by passing its `instructions` as `custom_instructions` to the compose/generate endpoints. Free.

Requires the `generations` scope.

**Example Request**

```
curl "https://api.algrow.online/api/thumbnails/instruction-presets" \
-H "Authorization: Bearer YOUR_API_KEY"
```

200 Success 400 Validation error 401 Auth failed

### `POST /api/thumbnails/instruction-presets`

Save (or update, by name) a reusable custom-instruction preset for thumbnail generation. Free.

Requires the `generations` scope.

**Request Body (JSON)**

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| name | string | Required | — | Preset name (max 60 chars). Saving an existing name updates it. |
| instructions | string | Required | — | The custom-instructions text (max 2000 chars). |

**Example Request**

```
curl -X POST "https://api.algrow.online/api/thumbnails/instruction-presets" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "Dark moody", "instructions": "dark moody palette, dramatic rim light"}'
```

200 Success 400 Validation error 401 Auth failed

### `DELETE /api/thumbnails/instruction-presets/{preset_id}`

Delete a custom-instruction preset by id (from the list endpoint). Free.

Requires the `generations` scope.

**Example Request**

```
curl -X DELETE "https://api.algrow.online/api/thumbnails/instruction-presets/12" \
-H "Authorization: Bearer YOUR_API_KEY"
```

200 Success 400 Validation error 401 Auth failed

### `POST /api/thumbnails/extract-video`

Resolve a YouTube URL or video ID to its title, channel, and max-resolution thumbnail. Free (no credits). Use the returned `thumbnail_url` as a reference for `POST /api/thumbnails`.

Requires the `generations` scope.

**Request Body (JSON)**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| url_or_id | string | Required | A YouTube watch URL, short URL, or bare 11-character video id. |

**Example Request**

```
curl -X POST "https://api.algrow.online/api/thumbnails/extract-video" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url_or_id": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"}'
```

200 Success 400 Validation error 401 Auth failed

### `POST /api/thumbnails/analyze`

Vision-analyse a thumbnail image into a structured design breakdown (composition, palette, text, focal points). Free (no credits).

Requires the `generations` scope.

**Request Body (JSON)**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| image_url | string | Required | Public URL of the thumbnail image to analyse. |

**Example Request**

```
curl -X POST "https://api.algrow.online/api/thumbnails/analyze" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"image_url": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg"}'
```

200 Success 400 Validation error 401 Auth failed

### `POST /api/thumbnails/compose`

Engineer an image-gen prompt from a title + a single reference, without generating. Free, synchronous. Stateless — there is no style id; save the returned `prompt` and pass it to `POST /api/thumbnails` as `final_prompt` to render.

Requires the `generations` scope. Two-step flow: `compose` → review/edit the prompt → `POST /api/thumbnails` with `final_prompt`.

**Request Body (JSON)**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| title | string | Required | Your new video title. |
| reference_url | string | Required | A YouTube URL, 11-char video id, or direct image URL. |
| reference_title | string | Optional | The reference's original video title (improves mapping). |
| custom_instructions | string | Optional | Extra art-direction. |

**Response 200 200**

```
{
  "success": true,
  "prompt": "A cinematic close-up …",
  "reference_url": "https://i.ytimg.com/vi/…/maxresdefault.jpg"
}
```

200 Success 400 Validation error 401 Auth failed

### `POST /api/thumbnails/compose-channel`

Channel-style compose without generating — resolve the channel, analyse its top thumbnails, match the best design to your title. Free, synchronous (~30–90s). Returns the engineered `prompt` + the channel's `source_thumb_urls`; pass both to `POST /api/thumbnails` (`final_prompt` + `reference_urls`) to render. Stateless.

Requires the `generations` scope.

**Request Body (JSON)**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| channel | string | Required | UC channel id, @handle, or channel URL. |
| title | string | Required | Your new video title. |
| custom_instructions | string | Optional | Extra art-direction. |

**Response 200 200**

```
{
  "success": true,
  "prompt": "…",
  "channel_id": "UC…",
  "matched_title": "…",
  "source_thumb_urls": ["https://…"]
}
```

200 Success 400 Validation error 401 Auth failed

### `GET /api/thumbnails/channel-presets`

List your saved per-channel thumbnail presets — instructions, subject face, style references, and generation defaults, saved together under a label. Returns the 50 most recent. Free.

Requires the `generations` scope.

**Example Request**

```
curl "https://api.algrow.online/api/thumbnails/channel-presets" \
-H "Authorization: Bearer YOUR_API_KEY"
```

**Example Response**

```
{
  "success": true,
  "presets": [
    {
      "id": 12,
      "label": "Main channel",
      "instructions": "high contrast, single subject, no text",
      "face_url": "https://audio.algrow.online/studio/references/ab12/face.png",
      "channel_style_name": "Documentary",
      "style_reference_urls": ["https://i.ytimg.com/vi/abc123/maxresdefault.jpg"],
      "aspect_ratio": "16:9",
      "resolution": "2K",
      "model": "nano-banana-pro"
    }
  ]
}
```

200 Success 401 Auth failed

### `POST /api/thumbnails/channel-presets`

Save a per-channel preset, or update an existing one by reusing its label. Only the fields you send are written; on update, everything you leave out keeps its current value. Free.

Requires the `generations` scope.

**Request Body (JSON)**

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| label | string | Required | — | Preset label. Sending an existing label updates that preset. |
| instructions | string | Optional | — | Custom instructions applied to every render made with this preset. |
| face_url | string | Optional | — | URL of the subject face to reuse. Takes precedence over `face_image_b64`. |
| face_image_b64 | string | Optional | — | Base64 face image (raw or a `data:` URL). Uploaded to storage and saved as `face_url` when no `face_url` is given. |
| content_type | string | Optional | image/png | MIME type for `face_image_b64`. |
| channel_style_id | string | Optional | — | Saved channel-style id to render in. |
| channel_style_name | string | Optional | — | Display name for the channel style. |
| style_reference_urls | array | Optional | — | Reference thumbnail URLs that define the look. |
| aspect_ratio | string | Optional | — | Default aspect ratio for renders, e.g. `16:9`. |
| resolution | string | Optional | — | Default resolution, e.g. `2K`. |
| model | string | Optional | — | Default image model. |

**Example Request**

```
curl -X POST "https://api.algrow.online/api/thumbnails/channel-presets" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"label": "Main channel", "instructions": "high contrast, single subject, no text", "aspect_ratio": "16:9"}'
```

**Example Response**

```
{
  "success": true,
  "preset": {"id": 12, "label": "Main channel", "instructions": "high contrast, single subject, no text", "aspect_ratio": "16:9"}
}
```

200 Success 400 Validation error 401 Auth failed

### `DELETE /api/thumbnails/channel-presets/{preset_id}`

Delete a per-channel preset by id (from the list endpoint). Free.

Requires the `generations` scope.

**Example Request**

```
curl -X DELETE "https://api.algrow.online/api/thumbnails/channel-presets/12" \
-H "Authorization: Bearer YOUR_API_KEY"
```

**Example Response**

```
{
  "success": true,
  "deleted": true
}
```

200 Success 400 Invalid preset id 401 Auth failed

### `GET /api/thumbnails/history`

Your generated-thumbnail history, newest first. One shared history across every path — the browser Studio, the MCP tools, and this API all appear. Each item carries the final image URL(s), the title it was made for, model, aspect ratio and `created_at`. Query params: `limit` (default 24, max 60) and `offset`; `has_more` signals another page. Free.

Requires the `generations` scope.

**Example Request**

```
curl "https://api.algrow.online/api/thumbnails/history?limit=24&offset=0" \
-H "Authorization: Bearer YOUR_API_KEY"
```

**Example Response**

```
{
  "success": true,
  "has_more": true,
  "items": [
    {
      "id": 1591,
      "title": "DON'T Make These 5 Going-Gray Mistakes",
      "image_urls": ["https://audio.algrow.online/studio/images/thumbnails/….png"],
      "model": "gpt-image-2.5",
      "aspect_ratio": "16:9",
      "source": "studio",
      "created_at": "2026-08-15T13:17:25"
    }
  ]
}
```

200 Success 401 Auth failed

### `POST /api/thumbnails/detect-people`

Check whether a reference image contains a person, so you can offer to swap in a real face before rendering. Cheaper and faster than a full analysis, and cached per image for six hours. Free.

Requires the `generations` scope.

**Request Body (JSON)**

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| image_url | string | Required | — | Reference image URL. YouTube thumbnail URLs and Algrow-hosted references both work. |

**Example Request**

```
curl -X POST "https://api.algrow.online/api/thumbnails/detect-people" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"image_url": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg"}'
```

**Example Response**

```
{
  "success": true,
  "has_person": true,
  "people": [{"description": "man, centre frame, facing camera"}],
  "cached": false
}
```

200 Success 400 Validation error 401 Auth failed

### `POST /api/thumbnails/crop-reference`

Crop a region out of a reference image and store it as a character reference. The crop happens server-side, so it works on images a browser canvas is not allowed to read back. Returns a hosted URL you can pass straight to generation as a character reference. Free.

Requires the `generations` scope.

**Request Body (JSON)**

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| image_url | string | Required | — | Image to crop. |
| crop | object | Required | — | Crop rectangle in normalized coordinates relative to the image's natural size: `{"x": 0.2, "y": 0.1, "w": 0.3, "h": 0.4}`, each between 0 and 1. |

**Example Request**

```
curl -X POST "https://api.algrow.online/api/thumbnails/crop-reference" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"image_url": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg", "crop": {"x": 0.2, "y": 0.1, "w": 0.3, "h": 0.4}}'
```

**Example Response**

```
{
  "success": true,
  "url": "https://audio.algrow.online/studio/references/ab12cd34/crop-9f2a.png"
}
```

200 Success 400 Validation error 401 Auth failed

### `POST /api/thumbnails/search-faces`

Search the web for photos of a named person so you can use one as a character reference. Pass the chosen photo through `/api/thumbnails/import-face` before rendering — some image hosts block our downloader. Free.

Requires the `generations` scope.

**Request Body (JSON)**

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| query | string | Required | — | Person to search for. Trimmed to 120 characters. |

**Example Request**

```
curl -X POST "https://api.algrow.online/api/thumbnails/search-faces" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "Serena Williams"}'
```

**Example Response**

```
{
  "success": true,
  "results": [
    {
      "thumb": "https://example.com/thumb.jpg",
      "full": "https://example.com/full.jpg",
      "title": "Serena Williams in 2025",
      "source": "example.com"
    }
  ]
}
```

200 Success 400 Validation error 401 Auth failed

### `POST /api/thumbnails/import-face`

Copy an external face photo into Algrow storage and return a stable URL the render pipeline can always fetch. Run every search result through this before using it as a reference. Free.

Requires the `generations` scope.

**Request Body (JSON)**

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| image_url | string | Required | — | Image to import. |
| fallback_url | string | Optional | — | Second URL to try when the first host blocks the download — e.g. the search result's thumbnail. |

**Example Request**

```
curl -X POST "https://api.algrow.online/api/thumbnails/import-face" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"image_url": "https://example.com/full.jpg", "fallback_url": "https://example.com/thumb.jpg"}'
```

**Example Response**

```
{
  "success": true,
  "url": "https://audio.algrow.online/studio/references/ab12cd34/face-search-7c1e.png"
}
```

200 Success 400 Download blocked / validation error 401 Auth failed

### `POST /api/thumbnails/swap-face`

Put a real face onto a thumbnail you already rendered. Queues like any other generation and returns a `task_id` to poll. Costs 1 credit, or 3 with `fast` enabled.

Requires the `generations` scope.

**Request Body (JSON)**

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| base_image_url | string | Required | — | The rendered thumbnail to edit. |
| face_url | string | Required | — | Face to place on it. Use an Algrow-hosted URL from `/api/thumbnails/import-face` or `/api/thumbnails/crop-reference`. |
| model | string | Optional | nano-banana-pro | Image model used for the swap. |
| aspect_ratio | string | Optional | 16:9 | Output aspect ratio. |
| resolution | string | Optional | 2K | Output resolution. |
| fast | boolean | Optional | false | Prioritised render. Costs 3 credits instead of 1. |

**Example Request**

```
curl -X POST "https://api.algrow.online/api/thumbnails/swap-face" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"base_image_url": "https://audio.algrow.online/studio/images/ab12/render.png", "face_url": "https://audio.algrow.online/studio/references/ab12/face.png"}'
```

**Example Response**

```
{
  "success": true,
  "task_id": "tsk_9f2a41c8",
  "state": "pending",
  "fast": false,
  "credits_used": 1,
  "message": "Face swap queued. Poll /api/thumbnails/status/{task_id} for progress."
}
```

Poll `GET /api/thumbnails/status/{task_id}` for the finished image. Credits are refunded automatically if the swap fails.

200 Queued 400 Validation error 401 Auth failed 402 Insufficient credits 429 Concurrent job limit 502 Face swap failed

### `POST /api/thumbnails/feedback`

Record a thumbs up or down on a generated thumbnail, with an optional comment. Sending the same `task_id` again updates the existing rating. Free.

Requires the `generations` scope.

**Request Body (JSON)**

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| rating | string | Required | — | `up` or `down`. |
| task_id | string | Optional | — | Task id of the generation being rated. Rating the same task again updates it. |
| image_url | string | Optional | — | URL of the rated image, when you don't have the task id. |
| feedback | string | Optional | — | Free-text comment (max 2,000 characters). |

**Example Request**

```
curl -X POST "https://api.algrow.online/api/thumbnails/feedback" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"task_id": "tsk_9f2a41c8", "rating": "down", "feedback": "face came out blurry"}'
```

**Example Response**

```
{
  "success": true
}
```

200 Success 400 Validation error 401 Auth failed
