Kolbo.AIKolbo.AI Docs
Developer API

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_id body field that routes the output into a specific project. See Projects.

Generate

Endpoint

POST /api/v1/generate/creative-director

Rate 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

FieldTypeRequiredDescription
promptstringYesCreative concept or brief. Must be a non-empty string, otherwise 400 INVALID_PROMPT.
scene_countnumberNoNumber 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).
modelstringNoModel 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_ratiostringNoApplied 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_idsarray of stringNoVisual 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_imagesarray of stringNoReference 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_idstringNoA single Moodboard ID applied to all scenes. Must be a valid ObjectId, otherwise 400.
moodboard_idsarray of stringNoPer-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_typestringNo"image" or "video" (default: "image")
durationnumberNoSeconds 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_promptbooleanNoAccepted but inert on this endpoint. Creative Director always writes and enhances each scene's prompt itself — sending false does not turn that off.
sound_enabledbooleanNoVideo 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).
resolutionstringNoResolution 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_idstringNoRoute 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
}
FieldTypeDescription
generation_idstringBatch id — poll and cancel with this
scene_countnumberScenes the batch actually planned
modelstringThe model you sent, or "smart_select" when you omitted it
poll_urlstringStatus path without the /api prefix — prepend https://api.kolbo.ai/api
poll_interval_hintnumberSuggested 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

StatusBody / codeCause
400INVALID_PROMPTprompt missing, empty, or not a string
400INVALID_MODELmodel sent as an array/object instead of a string identifier
400Invalid moodboard_id formatmoodboard_id is not a valid ObjectId
400moodboard_ids must be an arraymoodboard_ids sent as something other than an array
400Invalid ID in moodboard_idsOne of the moodboard_ids entries is not a valid ObjectId
403INSUFFICIENT_CREDITSBalance below the 5-credit floor described above
400SDK_PROJECT_INVALID_IDproject_id is not a valid ObjectId
404SDK_PROJECT_NOT_FOUNDNo project with that id is visible to you
403SDK_PROJECT_ACCESS_DENIEDYou hold less than edit permission on that project
429RATE_LIMIT_EXCEEDEDMore than 5 batch starts in a minute. The body carries resetAt and resetInSeconds
4xxGENERATION_ERRORAny 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 contractCreative Director
Start returns 200Start returns 202 Accepted. Do not test for 200 alone.
Start echoes session_id, project_id, credits_chargedNone of the three. The start body is exactly the seven keys shown above.
poll_url/v1/generate/{id}/statuspoll_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 jobstate 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 completionNever returned, even when state is completed — each scene is billed independently. Reconcile through Credits & Billing.
failed means nothing was producedA 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 failureerror is the fixed string "Creative Director generation failed". The real reason is per scene.
POST /v1/generate/{id}/cancelSame 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 statusstate returnedMeaning
pendingpendingAccepted, scenes not started
generatingprocessingAt least one scene is running
completedcompletedEvery scene finished successfully
partialcompletedSome 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.
failedfailedThe batch could not produce anything
cancelledcancelledCancelled

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/status

The 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

FieldTypeDescription
statestringpending | processing | completed | failed | cancelled. A batch where some scenes failed still reports completed — check each scene.
progressnumber0-100, computed as (completed + failed scenes) / total scenes
scenesarrayOne entry per scene, see below
errorstringPresent 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:

FieldTypeWhenDescription
scene_numbernumberalways1-based scene index
statusstringalwayspending | processing | completed | failed. Scenes have no cancelled state of their own — cancelling the batch stops them, and the batch-level state reports it.
titlestring | nullalwaysAI-generated scene title
progressnumberstatus: "processing"0-100 for that scene
image_urlsarraycompleted image scenesCDN image URLs
video_urlsarraycompleted video scenesCDN video URLs
errorstringstatus: "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.

StatusBodyCause
400Invalid generation ID format:id is not a valid ObjectId
404Generation not foundNo Creative Director batch with that id belongs to your API key
404Generation document not foundThe 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 model enables Smart Select, which picks a model per scene. The start response echoes "model": "smart_select". Pass a model identifier from GET /api/v1/models to 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 against GET /api/v1/models instead of trusting the echo.
  • Each scene is a full, independently billed generation, so batch cost scales with scene_count — and resolution / sound_enabled multipliers 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_id to apply a consistent style across all scenes, or moodboard_ids for per-scene styles. visual_dna_ids is 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 marked failed and carrying its own error.