Creative Director
Generate multi-scene creative sets from a single prompt using the Kolbo API.
The Creative Director generates multiple coordinated scenes from a single prompt. Give it a concept and scene count, and it produces a complete creative set — ideal for product showcases, storyboards, ad campaigns, and more.
All generation endpoints accept an optional
project_idbody field that routes the output into a specific project. See Projects.
Generate
Endpoint
POST /api/v1/generate/creative-directorRate limited to 10 requests/minute in production. The bucket is keyed by account (every API key you own shares it) and shared with the other non-image generation endpoints — video, music, speech, sound, 3D, video-to-video, lipsync, elements, first/last frame, chat and the cancel route all draw from the same 10/min counter. Image generation and image editing use a separate 30/min bucket. Status polling is not rate limited.
Creative Director adds a second, tighter guard on top of that shared bucket: batch starts are capped at 5 per minute per account and return 429 RATE_LIMIT_EXCEEDED with resetAt / resetInSeconds when exceeded.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
prompt | string | Yes | Creative concept or brief. Must be a non-empty string, otherwise 400 INVALID_PROMPT. |
scene_count | number | No | Number of scenes. Never rejected: 0 and any non-numeric value fall back to 4, a negative number clamps to 1, and anything above 8 clamps to 8 (default: 4). |
model | string | No | Model identifier from GET /api/v1/models, applied to every scene. Must be a string, otherwise 400 INVALID_MODEL. Omit it to let Smart Select pick per scene. An identifier that is not in the model catalogue is not rejected — Creative Director drops the pin and routes every scene through Smart Select instead, while the start response still echoes back the string you sent. |
aspect_ratio | string | No | Applied to every scene. Must be a value in the chosen model's supported_aspect_ratios from GET /api/v1/models (default: "1:1"). |
visual_dna_ids | array of string | No | Visual DNA IDs for character/product consistency. Hard cap of 8 per batch — extra IDs are silently dropped, not rejected. Per-scene assignment is index-based: scene 1 gets ID 1, scene 2 gets ID 2, and any scene past the end of the array falls back to the first ID. Pass a single ID to apply the same DNA to every scene. |
reference_images | array of string | No | Reference image URLs for style/composition. In image mode they apply to every scene; in video mode they are assigned one per scene, in order (URL 1 → scene 1). The cap is enforced silently after the batch starts, never as a 400: with no model pinned it is 8; with one pinned it is that model's max_reference_images from GET /api/v1/models (the server may apply a lower provider-side limit). Extra images are dropped. |
moodboard_id | string | No | A single Moodboard ID applied to all scenes. Must be a valid ObjectId, otherwise 400. |
moodboard_ids | array of string | No | Per-scene moodboard IDs, indexed from scene 1. A scene with no entry falls back to moodboard_id. Every element must be a valid ObjectId, otherwise 400. |
workflow_type | string | No | "image" or "video" (default: "image") |
duration | number | No | Seconds per scene, video mode only (default: 5). Must be a value in the model's supported_durations, or within its min_output_duration-max_output_duration, from GET /api/v1/models. |
enhance_prompt | boolean | No | Accepted but inert on this endpoint. Creative Director always writes and enhances each scene's prompt itself — sending false does not turn that off. |
sound_enabled | boolean | No | Video mode only — generate native audio on models that support it. Ignored in image mode. Applies the model's sound_credit_multiplier to every scene (default: false). |
resolution | string | No | Resolution tier applied to every scene. Values are model-dependent — read supported_resolutions on the target model via GET /api/v1/models. Multiplied across all scenes, so a higher tier can substantially increase a batch's cost — see Credit Multipliers. |
project_id | string | No | Route the batch into a specific project. Defaults to your auto-created "API Generations" project. |
Creative Director requires a minimum balance of 5 credits before the batch starts. Below that the request fails immediately with 403 INSUFFICIENT_CREDITS — the real, per-scene cost is reserved afterwards by each scene.
Example
curl -X POST https://api.kolbo.ai/api/v1/generate/creative-director \
-H "X-API-Key: kolbo_live_..." \
-H "Content-Type: application/json" \
-d '{
"prompt": "Product showcase for a premium red sneaker",
"scene_count": 4,
"aspect_ratio": "16:9"
}'Response
A successful start returns HTTP 202 Accepted — the batch is queued, not finished. Every other generation endpoint returns 200, so do not test for 200 alone.
{
"success": true,
"generation_id": "6612f0a1b2c3d4e5f6a7b8c9",
"type": "creative_director",
"scene_count": 4,
"model": "smart_select",
"poll_url": "/v1/generate/creative-director/6612f0a1b2c3d4e5f6a7b8c9/status",
"poll_interval_hint": 5
}| Field | Type | Description |
|---|---|---|
generation_id | string | Batch id — poll and cancel with this |
scene_count | number | Scenes the batch actually planned |
model | string | The model you sent, or "smart_select" when you omitted it |
poll_url | string | Status path without the /api prefix — prepend https://api.kolbo.ai/api |
poll_interval_hint | number | Suggested seconds between polls |
Unlike the other generation endpoints, the Creative Director start response carries no session_id, project_id or credits_charged. Those fields belong to the shared start envelope; this route returns its own shape with exactly the keys shown above.
On failure the endpoint returns success: false with code set to GENERATION_ERROR (the batch could not start) or TRACKING_ERROR (the batch started but its id could not be recorded, so it cannot be polled).
Errors
| Status | Body / code | Cause |
|---|---|---|
| 400 | INVALID_PROMPT | prompt missing, empty, or not a string |
| 400 | INVALID_MODEL | model sent as an array/object instead of a string identifier |
| 400 | Invalid moodboard_id format | moodboard_id is not a valid ObjectId |
| 400 | moodboard_ids must be an array | moodboard_ids sent as something other than an array |
| 400 | Invalid ID in moodboard_ids | One of the moodboard_ids entries is not a valid ObjectId |
| 403 | INSUFFICIENT_CREDITS | Balance below the 5-credit floor described above |
| 400 | SDK_PROJECT_INVALID_ID | project_id is not a valid ObjectId |
| 404 | SDK_PROJECT_NOT_FOUND | No project with that id is visible to you |
| 403 | SDK_PROJECT_ACCESS_DENIED | You hold less than edit permission on that project |
| 429 | RATE_LIMIT_EXCEEDED | More than 5 batch starts in a minute. The body carries resetAt and resetInSeconds |
| 4xx | GENERATION_ERROR | Any other downstream Creative Director rejection, re-wrapped into the SDK envelope with the controller's own message |
Completion Contract
Polling is the only completion mechanism. Kolbo never calls you back. There is no webhook, no callback_url field on the request body, no server-sent events, and no route delivers outbound notifications. The batch id is registered as SDK-originated the moment the start response is written, so the shared progress emitter drops its events — but Creative Director's own per-scene emits write to Socket.IO directly and never consult that registry, so a socket you authenticate with an API key may still see scene chatter. Those events are the web app's internal transport: undocumented, unversioned and unsafe to build on. After the POST, loop against the status route below.
Read Polling & Cancellation for the shared concepts. Creative Director is the one batch flow that is partly on the generic contract — the generic status and cancel routes both accept a batch id — but its payload shape is its own:
| Generic generation contract | Creative Director |
|---|---|
Start returns 200 | Start returns 202 Accepted. Do not test for 200 alone. |
Start echoes session_id, project_id, credits_charged | None of the three. The start body is exactly the seven keys shown above. |
poll_url → /v1/generate/{id}/status | poll_url → /v1/generate/creative-director/{id}/status. The generic route also works: it recognises the batch and internally delegates to the dedicated one, returning a byte-identical body. |
One state for the whole job | state for the batch plus an independent status on every scene. Scene statuses are what carry the actionable detail. |
result.urls[] | scenes[].image_urls / scenes[].video_urls. There is no result object on this route. |
credits_used / credits_breakdown on completion | Never returned, even when state is completed — each scene is billed independently. Reconcile through Credits & Billing. |
failed means nothing was produced | A batch where some scenes failed still reports state: "completed" with usable URLs on the scenes that worked. Only a batch where the whole run collapsed reports failed. |
error explains the failure | error is the fixed string "Creative Director generation failed". The real reason is per scene. |
POST /v1/generate/{id}/cancel | Same route, and it is the only way to cancel a batch. Cancelling stops every scene still in flight. |
Batch lifecycle
pending → processing → completed (every scene finished, or some failed — check each scene)
→ failed (the batch itself collapsed)
→ cancelled (you called the cancel route)state is a normalized view of the underlying batch record, which has one extra value the API deliberately hides:
| Underlying batch status | state returned | Meaning |
|---|---|---|
pending | pending | Accepted, scenes not started |
generating | processing | At least one scene is running |
completed | completed | Every scene finished successfully |
partial | completed | Some scenes succeeded, some failed. Collapsed into completed on purpose — a partial batch is terminal and its successful scenes are ready. Detect it by looking for status: "failed" scenes. |
failed | failed | The batch could not produce anything |
cancelled | cancelled | Cancelled |
Anything the map does not recognise falls through to processing, so treat completed, failed and cancelled as your terminal set and keep polling on everything else.
Poll Status
Creative Director has a dedicated status endpoint that returns per-scene progress.
Endpoint
GET /api/v1/generate/creative-director/:id/statusThe generic GET /api/v1/generate/:generationId/status accepts a Creative Director id too — it delegates to this route and returns the identical body. See Polling & Cancellation.
Example
curl https://api.kolbo.ai/api/v1/generate/creative-director/6612f0a1b2c3d4e5f6a7b8c9/status \
-H "X-API-Key: kolbo_live_..."Response Fields
| Field | Type | Description |
|---|---|---|
state | string | pending | processing | completed | failed | cancelled. A batch where some scenes failed still reports completed — check each scene. |
progress | number | 0-100, computed as (completed + failed scenes) / total scenes |
scenes | array | One entry per scene, see below |
error | string | Present only when state is failed. Always the fixed string "Creative Director generation failed" — the actionable detail is on the individual scene entries. |
A Creative Director status body carries no credits_used or credits_breakdown, even when state is completed — those fields exist only on the generic status route for non-batch types. To reconcile what a batch cost, read the credit records from Credits & Billing.
Each scene carries:
| Field | Type | When | Description |
|---|---|---|---|
scene_number | number | always | 1-based scene index |
status | string | always | pending | processing | completed | failed. Scenes have no cancelled state of their own — cancelling the batch stops them, and the batch-level state reports it. |
title | string | null | always | AI-generated scene title |
progress | number | status: "processing" | 0-100 for that scene |
image_urls | array | completed image scenes | CDN image URLs |
video_urls | array | completed video scenes | CDN video URLs |
error | string | status: "failed" | Why that scene failed — the rest of the batch is unaffected |
Errors
There is no request body and no rate limiter on this route, so a normal poll loop is never throttled.
| Status | Body | Cause |
|---|---|---|
| 400 | Invalid generation ID format | :id is not a valid ObjectId |
| 404 | Generation not found | No Creative Director batch with that id belongs to your API key |
| 404 | Generation document not found | The batch was tracked but its underlying record no longer exists |
Response (In Progress)
{
"success": true,
"generation_id": "6612f0a1b2c3d4e5f6a7b8c9",
"type": "creative_director",
"state": "processing",
"progress": 50,
"scenes": [
{
"scene_number": 1,
"status": "completed",
"title": "Hero Shot",
"image_urls": ["https://media.kolbo.ai/images/..."]
},
{
"scene_number": 2,
"status": "completed",
"title": "Detail Close-up",
"image_urls": ["https://media.kolbo.ai/images/..."]
},
{
"scene_number": 3,
"status": "processing",
"title": "Lifestyle Context",
"progress": 60
},
{
"scene_number": 4,
"status": "pending",
"title": "Brand Statement"
}
]
}Response (Completed)
{
"success": true,
"generation_id": "6612f0a1b2c3d4e5f6a7b8c9",
"type": "creative_director",
"state": "completed",
"progress": 100,
"scenes": [
{
"scene_number": 1,
"status": "completed",
"title": "Hero Shot",
"image_urls": ["https://media.kolbo.ai/images/..."]
},
{
"scene_number": 2,
"status": "completed",
"title": "Detail Close-up",
"image_urls": ["https://media.kolbo.ai/images/..."]
},
{
"scene_number": 3,
"status": "completed",
"title": "Lifestyle Context",
"image_urls": ["https://media.kolbo.ai/images/..."]
},
{
"scene_number": 4,
"status": "completed",
"title": "Brand Statement",
"image_urls": ["https://media.kolbo.ai/images/..."]
}
]
}Response (Partial — some scenes failed)
The batch is terminal and reports state: "completed". The failed scene carries its own error and no URLs; every other scene is ready to use.
{
"success": true,
"generation_id": "6612f0a1b2c3d4e5f6a7b8c9",
"type": "creative_director",
"state": "completed",
"progress": 100,
"scenes": [
{
"scene_number": 1,
"status": "completed",
"title": "Hero Shot",
"image_urls": ["https://media.kolbo.ai/images/..."]
},
{
"scene_number": 2,
"status": "failed",
"title": "Detail Close-up",
"error": "Content policy: the prompt was rejected by the provider"
}
]
}state: "completed" does not mean every scene succeeded. Always filter scenes by status === "completed" before collecting URLs, and surface the error on any scene that failed. progress reaches 100 when completed + failed scenes equal the total, so a batch with failures still finishes at 100.
Response (Failed)
Only when the batch itself collapsed. error is the same fixed string every time:
{
"success": true,
"generation_id": "6612f0a1b2c3d4e5f6a7b8c9",
"type": "creative_director",
"state": "failed",
"progress": 0,
"scenes": [],
"error": "Creative Director generation failed"
}Note the HTTP status is still 200 and success is still true — a failed batch is a successful poll. Branch on state, never on the HTTP code. When scenes is non-empty, each entry's own error is the only place a real reason appears.
Video Mode
Generate coordinated video scenes instead of images by setting workflow_type to "video":
curl -X POST https://api.kolbo.ai/api/v1/generate/creative-director \
-H "X-API-Key: kolbo_live_..." \
-H "Content-Type: application/json" \
-d '{
"prompt": "30-second sneaker commercial with dynamic angles",
"scene_count": 4,
"workflow_type": "video",
"duration": 5,
"aspect_ratio": "16:9"
}'When using video mode, each completed scene returns video_urls instead of (or in addition to) image_urls in the status response.
Add "sound_enabled": true to get native audio on video models that support it. It is applied per scene and multiplies each scene's cost by the model's sound_credit_multiplier.
Video batches are much slower than image batches — each scene is a full video generation running in parallel. Poll for tens of minutes rather than seconds, and use POST /api/v1/generate/:generationId/cancel if you need to stop a batch early.
Cancel a Batch
Creative Director batches use the shared cancel route. Cancelling the batch also stops every scene still in flight, and the response reports how many with batch_cancelled_count:
curl -X POST https://api.kolbo.ai/api/v1/generate/6612f0a1b2c3d4e5f6a7b8c9/cancel \
-H "X-API-Key: kolbo_live_..."Cancel draws from the same 10/min generation bucket as the start endpoint, so cancelling a batch consumes one of the requests you could have spent starting one. A batch that already reached a terminal state returns 409 CANNOT_CANCEL with current_status — an answer, not a failure.
See Polling & Cancellation for the full contract.
With Reference Images
Pass reference images to guide the style and content of generated scenes:
curl -X POST https://api.kolbo.ai/api/v1/generate/creative-director \
-H "X-API-Key: kolbo_live_..." \
-H "Content-Type: application/json" \
-d '{
"prompt": "Product showcase in various lifestyle settings",
"scene_count": 4,
"reference_images": ["https://example.com/product-front.jpg", "https://example.com/product-side.jpg"],
"aspect_ratio": "1:1"
}'In image mode every reference image guides every scene. In video mode the array is split across scenes instead — the first URL is attached to scene 1, the second to scene 2, and so on.
With Visual DNA
Combine Creative Director with Visual DNA to generate consistent character or product scenes:
curl -X POST https://api.kolbo.ai/api/v1/generate/creative-director \
-H "X-API-Key: kolbo_live_..." \
-H "Content-Type: application/json" \
-d '{
"prompt": "Fashion lookbook for Emma in urban settings",
"scene_count": 6,
"visual_dna_ids": ["6601a1b2c3d4e5f6a7b8c9d0"],
"aspect_ratio": "9:16"
}'JavaScript Example
const API_KEY = "kolbo_live_..."; // Replace with your API key
async function generateCreativeDirector() {
const BASE = "https://api.kolbo.ai/api";
// Start generation (Smart Select picks the best model automatically)
const res = await fetch(`${BASE}/v1/generate/creative-director`, {
method: "POST",
headers: {
"X-API-Key": API_KEY,
"Content-Type": "application/json"
},
body: JSON.stringify({
prompt: "Product showcase for artisan coffee brand",
scene_count: 4,
aspect_ratio: "16:9"
})
});
const { generation_id, poll_url } = await res.json();
console.log(`Started generation: ${generation_id}`);
// Poll for results
let result;
do {
await new Promise(r => setTimeout(r, 5000));
const status = await fetch(`${BASE}${poll_url}`, {
headers: { "X-API-Key": API_KEY }
});
result = await status.json();
console.log(`Progress: ${result.progress}%`);
} while (result.state === "processing" || result.state === "pending");
// Collect all scene images
const allImages = result.scenes
.filter(s => s.status === "completed")
.flatMap(s => s.image_urls);
console.log(`Generated ${allImages.length} images across ${result.scenes.length} scenes`);
allImages.forEach(url => console.log(url));
}
generateCreativeDirector();Python Example
import requests
import time
API_KEY = "kolbo_live_..." # Replace with your API key
BASE = "https://api.kolbo.ai/api"
# Start generation (Smart Select picks the best model automatically)
r = requests.post(
f"{BASE}/v1/generate/creative-director",
headers={"X-API-Key": API_KEY},
json={
"prompt": "Storyboard for a 30-second sneaker commercial",
"scene_count": 6,
"aspect_ratio": "16:9"
}
)
gen = r.json()
print(f"Started generation: {gen['generation_id']}")
# Poll for results
while True:
time.sleep(5)
s = requests.get(
f"{BASE}{gen['poll_url']}",
headers={"X-API-Key": API_KEY}
).json()
completed = sum(1 for sc in s["scenes"] if sc["status"] == "completed")
print(f"Progress: {s['progress']}% ({completed}/{len(s['scenes'])} scenes)")
if s["state"] not in ("processing", "pending"):
break
# Print results
for scene in s["scenes"]:
if scene["status"] == "completed":
print(f"Scene {scene['scene_number']}: {scene['title']}")
for url in scene["image_urls"]:
print(f" {url}")With Moodboard
Apply a moodboard to all scenes:
curl -X POST https://api.kolbo.ai/api/v1/generate/creative-director \
-H "X-API-Key: kolbo_live_..." \
-H "Content-Type: application/json" \
-d '{
"prompt": "Product showcase for a premium sneaker",
"scene_count": 4,
"moodboard_id": "6601a1b2c3d4e5f6a7b8c9d0",
"aspect_ratio": "16:9"
}'Or use different moodboards per scene with moodboard_ids (one moodboard ID per scene, indexed from scene 1):
curl -X POST https://api.kolbo.ai/api/v1/generate/creative-director \
-H "X-API-Key: kolbo_live_..." \
-H "Content-Type: application/json" \
-d '{
"prompt": "Brand campaign across three distinct moods",
"scene_count": 3,
"moodboard_ids": ["MOODBOARD_ID_1", "MOODBOARD_ID_2", "MOODBOARD_ID_3"]
}'Replace MOODBOARD_ID_1, etc. with real IDs from GET /api/v1/moodboards.
Use GET /api/v1/moodboards to list available moodboards. See Moodboards for details.
Tips
- Omitting
modelenables Smart Select, which picks a model per scene. The start response echoes"model": "smart_select". Pass amodelidentifier fromGET /api/v1/modelsto pin every scene to one model. A typo or a stale identifier fails quietly rather than loudly: the batch still runs, every scene falls back to Smart Select, and the start response echoes the string you sent — so verify the identifier againstGET /api/v1/modelsinstead of trusting the echo. - Each scene is a full, independently billed generation, so batch cost scales with
scene_count— andresolution/sound_enabledmultipliers apply to every scene. - The AI generates the scene titles and per-scene prompts itself from your brief.
- Creative Director works well with Visual DNA for maintaining character consistency across scenes.
- Use
moodboard_idto apply a consistent style across all scenes, ormoodboard_idsfor per-scene styles.visual_dna_idsis indexed the same way. - Scenes run in parallel, so use the per-scene status to show progressive results in your UI instead of waiting for the whole batch.
- A scene that fails does not fail the batch — the batch still reaches
state: "completed"with that scene markedfailedand carrying its ownerror.