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 30 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 and write endpoints — video, music, speech, sound, 3D, video-to-video, lipsync, elements, first/last frame, chat, Visual DNA create/update, media upload and the cancel route all draw from the same 30/min counter. Requests that are rejected (any 4xx/5xx) do not consume the budget. Image generation and image editing use their own, separate 30/min bucket. Status polling is not rate limited. When this limiter trips the 429 body carries limit, window_seconds and retryAfter.

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 with code: "RATE_LIMIT_EXCEEDED". The SDK envelope only carries success, error and code for this one — the seconds until reset are stated inside the error message, not as separate fields.

Request Body

FieldTypeRequiredDescription
promptstringYesCreative concept or brief. Must be a non-empty string, otherwise 400 INVALID_PROMPT. Maximum 50,000 characters (400 PROMPT_TOO_LONG). #Name moodboard mentions inside the prompt are resolved against your library (an explicit moodboard_id wins). @Name Visual DNA mentions are resolved only when the pinned model supports Visual DNA — with Smart Select, pass the DNA in visual_dna_ids instead.
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. Use a value from the chosen model's supported_aspect_ratios in GET /api/v1/models (default: "1:1").
visual_dna_idsarray of stringNoVisual DNA IDs for character/product consistency. Up to 20 IDs are read — extras 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. If none of the IDs is accessible to you the start fails with 403 VISUAL_DNA_ACCESS_DENIED.
reference_imagesarray of stringNoReference image URLs. Image mode: they guide every scene. 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). Your images take priority; Visual DNA images fill whatever slots remain. Extra images are dropped. Video mode: each URL is attached to exactly one scene, in order (URL 1 → scene 1), so the array length must equal the effective scene_count, otherwise 400 SCENE_COUNT_IMAGE_MISMATCH.
moodboard_idstringNoA single Moodboard ID applied to all scenes. Must be a valid ObjectId, otherwise 400; an ID you cannot access returns 404 MOODBOARD_NOT_FOUND.
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). Use 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.
font_idsarray of stringNoImage mode only. Up to 3 ready personal font family IDs (24-character hex) applied to every scene; duplicates are removed. Anything else (more than 3, a non-array, a malformed ID) is rejected with 400. With Smart Select, scenes are routed only to models with supports_custom_fonts: true in GET /api/v1/models; if you pin a model, pick one that supports custom fonts.
project_idstringNoRoute the batch into a specific project. Defaults to your auto-created "API Generations" project.
session_idstringNoAdd this batch to an existing Creative Director session of yours (the start response does not return one — look it up with GET /api/v1/sessions) instead of the daily API session. The project is taken from the session, so project_id is ignored. Invalid id → 400 SDK_SESSION_INVALID_ID; unknown, deleted or not a Creative Director session → 404 SDK_SESSION_NOT_FOUND. Write access is checked on the session's project, so the SDK_PROJECT_* errors below also apply.

Creative Director checks credits twice before the batch starts. First a 5-credit floor: below it the request fails immediately with 403 INSUFFICIENT_CREDITS (body also carries balance, required and pricing_url). Then an estimate for the whole batch (scene count × model cost, × duration in video mode): if your balance cannot cover it the start fails with 403 INSUFFICIENT_CREDITS (or SUBSCRIPTION_INACTIVE), and a project with a budget that cannot cover it fails with 403 PROJECT_BUDGET_EXCEEDED. The real, per-scene cost is reserved afterwards by each scene.

Your account's active Color DNA palette is applied to the whole batch. Unlike the single-image and video endpoints, this route has no per-call opt-out — deactivate the palette first if a batch must ignore it.

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.

When Creative Director itself rejects the batch, the response is re-wrapped into { success: false, error, code } with the original HTTP status. code is the downstream code when there is one (see the table below), otherwise GENERATION_ERROR; any extra fields the downstream error carried are dropped. TRACKING_ERROR means the batch started but its id could not be recorded — in the 500 case the server cancels the batch for you, so nothing is left running that you cannot poll.

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
400INVALID_FONT_IDSInvalid font_ids (Select up to 3 font families / font_ids must be an array)
400PROMPT_TOO_LONGprompt longer than 50,000 characters
400SCENE_COUNT_IMAGE_MISMATCHVideo mode: number of reference_images differs from the effective scene_count
400NSFW_BLOCKEDThe prompt was blocked by your account's content filter before anything was charged
400SDK_PROJECT_INVALID_ID / SDK_SESSION_INVALID_IDproject_id / session_id is not a valid ObjectId
403INSUFFICIENT_CREDITSBalance below the 5-credit floor, or below the batch estimate, described above
403SUBSCRIPTION_INACTIVEThe batch estimate check found no usable subscription
403PROJECT_BUDGET_EXCEEDEDThe target project's budget cannot cover the batch estimate
403SDK_PROJECT_ACCESS_DENIEDYou hold less than edit permission on that project
403VISUAL_DNA_ACCESS_DENIEDNone of the visual_dna_ids is accessible to you
404SDK_PROJECT_NOT_FOUND / SDK_SESSION_NOT_FOUNDNo project / Creative Director session with that id is visible to you
404MOODBOARD_NOT_FOUNDmoodboard_id does not exist or is not accessible
404NOT_FOUNDA visual_dna_ids entry belongs to a restricted collection your key cannot use
429RATE_LIMIT_EXCEEDEDMore than 5 batch starts in a minute. The wait in seconds is in the error message
429(no code)The shared 30/min generation bucket is exhausted. Body carries limit, window_seconds, retryAfter
500TRACKING_ERRORThe batch could not be tracked and was cancelled
4xxGENERATION_ERRORAny other downstream Creative Director rejection that carries no code of its own

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.

To base each video scene on one of your own images, pass exactly one reference_images URL per scene (scene_count must equal the number of URLs). font_ids does not apply to video batches.

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_..."

batch_cancelled_count is omitted when no scene was still in flight. Cancel draws from the same 30/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 — and the number of URLs must equal scene_count, otherwise the start fails with 400 SCENE_COUNT_IMAGE_MISMATCH.

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. An identifier the catalog does not know returns 400 MODEL_NOT_FOUND (with near-match suggestions) before the batch starts; auto-select aliases such as "auto" behave like omitting model.
  • 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.