Kolbo.AIKolbo.AI Docs
Developer API

Color Palettes

Color DNA — save a palette and strict-grade every generation in a project to those colors.

A Color DNA palette is a named set of 1-10 colors. Activating a palette turns it into a strict color grade for a project: a plain-language directive ("dominant terracotta, secondary deep navy, accent warm gold…") is woven into the prompt of every graded generation in that project, telling the model to grade lighting, atmosphere, set dressing and wardrobe to those colors while leaving the subject and action alone. See the table below for exactly which endpoints are graded.

A grade belongs to a project, not to your account. There is no account-level default — activating a palette requires a projectId, and a generation is only graded when it lands in a project that has one active. SDK generations land in the auto-created "API Generations" project unless you pass project_id, so that is usually the project you need to activate on. Get its id from GET /api/v1/projects (the entry with is_default: true).

Where the grade is applied

EndpointGradedPer-request opt-out
POST /api/v1/generate/imageYesskip_color_palette: true
POST /api/v1/generate/image-editYesskip_color_palette: true
POST /api/v1/generate/video (text-to-video)Yesskip_color_palette: true
POST /api/v1/generate/creative-directorYes (all scenes)none — the endpoint does not accept skip_color_palette
POST /api/v1/generate/video/from-imageNoskip_color_palette is accepted but has no effect

skip_color_palette is a boolean, optional, default false (grade applied). It only affects the single request it is sent on. Only the JSON literal true opts out — the string "true" is mapped to false by the SDK layer.

Image-to-video is not graded. Grading is mode-gated to text-to-video — a source image already fixes the colors, so grading the prompt would promise a look the output never takes. POST /generate/video/from-image therefore ignores the project's palette, and skip_color_palette there is a no-op.

Every other generation endpoint (Elements, first/last frame, video-to-video, lipsync, 3D, speech, sound, music) is ungraded and does not accept skip_color_palette.

The directive is composed from each color's role and name in words only — hex codes are deliberately never sent to the model, because image models render literal hex strings and color strips as visible artifacts. A color saved without a name gets the nearest name from a built-in color table.

Endpoints

GET    /api/v1/color-palettes
POST   /api/v1/color-palettes
POST   /api/v1/color-palettes/analyze
PUT    /api/v1/color-palettes/:id
DELETE /api/v1/color-palettes/:id
POST   /api/v1/color-palettes/:id/activate
POST   /api/v1/color-palettes/deactivate

Where a project id is accepted it is spelled projectId (camelCase), unlike the generation endpoints which take project_id. Only four routes accept it at all: list (query string), create, activate and deactivate (body). Update, delete and analyze have no project parameter — and because the create/update bodies are validated strictly, sending projectId (or any other unlisted field, including project_id) to PUT /color-palettes/:id is a 400 Validation error.

Error envelope. Successful responses use the normal SDK shape ({"success": true, …}), and so do errors raised inside the handler ({"success": false, "error": "…"}). But the create/update body validator and the shared rate limiter run before the handler, so their rejections come back in the underlying app shape instead — {"status": false, "message": "Validation error", "details": [...]} for a bad body, and {"status": false, "error": "Too many generation requests", "message": "…", "retryAfter": 60} for the 120/min bucket. Branch on the HTTP status code, not on the presence of a success field, when handling errors from these seven routes.

List Palettes

Returns your personal palettes plus the palettes shared through your active organization, newest first. When projectId is supplied, the palette currently grading that project is included even if a teammate owns it, and is_active marks it.

Endpoint

GET /api/v1/color-palettes

Query Parameters

ParameterTypeRequiredConstraint
projectIdstringNoProject id. Determines which palette (if any) comes back with is_active: true. Without it — or with an id you cannot access — every palette is reported is_active: false. An unreadable id is ignored, not an error.
pageintegerNoDefault 1. Clamped to a minimum of 1.
limitintegerNoDefault 50. Clamped to 1-100; a larger value is silently capped, not rejected.

Example

curl "https://api.kolbo.ai/api/v1/color-palettes?projectId=65f1c8a2e4b0a3c1d9f5e789" \
  -H "X-API-Key: kolbo_live_..."

Response

{
  "success": true,
  "color_palettes": [
    {
      "id": "66a2b3c4d5e6f7a8b9c0d1e2",
      "name": "Terracotta & Deep Navy",
      "colors": [
        { "hex": "#E2725B", "name": "terracotta", "role": "dominant" },
        { "hex": "#0F1E3D", "name": "deep navy", "role": "secondary" },
        { "hex": "#E8C170", "name": "warm gold", "role": "accent" }
      ],
      "source_image_urls": ["https://cdn.kolbo.ai/uploads/ref1.jpg"],
      "is_active": true,
      "content_scope": "personal",
      "created_at": "2026-06-02T10:11:12.000Z",
      "updated_at": "2026-06-02T10:11:12.000Z"
    }
  ],
  "pagination": { "page": 1, "limit": 50, "total": 3, "pages": 1 }
}

content_scope is "personal" or "organization". Palettes created through this API are always "personal". Organization palettes come from the in-app org admin surface and are stored with no owner, so they are list-only here — update, delete and activate all match on ownership and return 404 for them. To grade a project with an org palette's colors, copy its colors into a new palette of your own.

Analyze Images

Extracts a palette from reference images with deterministic pixel math (median-cut quantization) — no model call, no credits, and nothing is saved. Feed the returned colors straight into the create endpoint.

Endpoint

POST /api/v1/color-palettes/analyze

Request Body

ParameterTypeRequiredConstraint
image_urlsstring[]Yes1-5 publicly reachable image URLs. Private/internal addresses are rejected, redirects are not followed, and each image is capped at 20 MB.

Images that cannot be downloaded are skipped; if none of them can be downloaded the request returns 400. The response contains up to 6 colors, ordered by pixel population, with role assigned as dominant (first), secondary (second), then accent. Near-duplicate colors are merged, so you can get back fewer than 6. Each color's name is the nearest entry in a built-in color-name table, and the palette name is built from the first two color names.

Unlike create/update, this body is not strictly validated — any field other than image_urls is silently discarded. If image_urls is missing or out of range the error message names the internal field: "imageUrls must be an array of 1-5 URLs". Send image_urls.

Example

curl -X POST https://api.kolbo.ai/api/v1/color-palettes/analyze \
  -H "X-API-Key: kolbo_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "image_urls": [
      "https://cdn.kolbo.ai/uploads/moodboard-1.jpg",
      "https://cdn.kolbo.ai/uploads/moodboard-2.jpg"
    ]
  }'

Response

{
  "success": true,
  "name": "Terracotta & Deep Navy",
  "colors": [
    { "hex": "#E2725B", "name": "terracotta", "role": "dominant" },
    { "hex": "#0F1E3D", "name": "deep navy", "role": "secondary" },
    { "hex": "#E8C170", "name": "warm gold", "role": "accent" }
  ]
}

Create Palette

Endpoint

POST /api/v1/color-palettes

Request Body

ParameterTypeRequiredConstraint
namestringYes1-100 characters after trimming.
colorsobject[]Yes1-10 entries. See the color object below.
source_image_urlsstring[]NoMax 5 entries, each a valid URI. Stored as provenance only. A 6th entry is a 400.
is_activebooleanNoDefault true. Only has an effect when projectId is also sent; false suppresses activation.
projectIdstringNoProject the new palette should immediately grade. Checked only when the palette is actually being activated (i.e. is_active is not false) — then you must be the project owner or a member shared with edit or full permission, otherwise 403, as is an id you cannot access or that does not exist. With is_active: false this field is ignored entirely and no access check runs.

Color object:

FieldTypeRequiredConstraint
hexstringYes#RRGGBB, exactly 6 hex digits.
namestringNoUp to 60 characters after trimming; the empty string is accepted. Used verbatim in the prompt directive; when omitted or empty, the nearest built-in color name is used instead.
rolestringNodominant | secondary | accent | background. Stored default is accent, so responses always carry a role even when you omit it.

is_active: true without projectId does not activate anything — the palette is saved to your library and the response comes back with is_active: false. Send projectId, or call the activate endpoint afterwards.

Example

curl -X POST https://api.kolbo.ai/api/v1/color-palettes \
  -H "X-API-Key: kolbo_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Terracotta & Deep Navy",
    "colors": [
      { "hex": "#E2725B", "name": "terracotta", "role": "dominant" },
      { "hex": "#0F1E3D", "name": "deep navy", "role": "secondary" },
      { "hex": "#E8C170", "name": "warm gold", "role": "accent" }
    ],
    "projectId": "65f1c8a2e4b0a3c1d9f5e789"
  }'

Response

{
  "success": true,
  "color_palette": {
    "id": "66a2b3c4d5e6f7a8b9c0d1e2",
    "name": "Terracotta & Deep Navy",
    "colors": [
      { "hex": "#E2725B", "name": "terracotta", "role": "dominant" },
      { "hex": "#0F1E3D", "name": "deep navy", "role": "secondary" },
      { "hex": "#E8C170", "name": "warm gold", "role": "accent" }
    ],
    "source_image_urls": [],
    "is_active": true,
    "content_scope": "personal",
    "created_at": "2026-06-02T10:11:12.000Z",
    "updated_at": "2026-06-02T10:11:12.000Z"
  }
}

Update Palette

Renames a palette and/or replaces its colors. Only the owner of the palette can update it — anyone else gets 404. Activation is not affected.

Endpoint

PUT /api/v1/color-palettes/:id

Request Body

ParameterTypeRequiredConstraint
namestringNo1-100 characters after trimming.
colorsobject[]No1-10 entries, same object shape as create. Full replacement — omit to keep the current colors.
source_image_urlsstring[]NoMax 5 entries, each a valid URI. Replaces the stored list.

Example

curl -X PUT https://api.kolbo.ai/api/v1/color-palettes/66a2b3c4d5e6f7a8b9c0d1e2 \
  -H "X-API-Key: kolbo_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "name": "Terracotta & Navy v2" }'

Response

{
  "success": true,
  "color_palette": {
    "id": "66a2b3c4d5e6f7a8b9c0d1e2",
    "name": "Terracotta & Navy v2",
    "colors": [{ "hex": "#E2725B", "name": "terracotta", "role": "dominant" }],
    "source_image_urls": [],
    "is_active": false,
    "content_scope": "personal",
    "created_at": "2026-06-02T10:11:12.000Z",
    "updated_at": "2026-06-02T12:30:00.000Z"
  }
}

The is_active in this particular response is read from a legacy stored field and is always false for palettes created through the API — it is not project-relative. To see which palette is grading a project, call GET /api/v1/color-palettes?projectId=….

Delete Palette

Owner only (404 otherwise). Every project that was grading with this palette has its grade cleared, so those projects go back to generating ungraded.

Endpoint

DELETE /api/v1/color-palettes/:id

Example

curl -X DELETE https://api.kolbo.ai/api/v1/color-palettes/66a2b3c4d5e6f7a8b9c0d1e2 \
  -H "X-API-Key: kolbo_live_..."

Response

{ "success": true, "id": "66a2b3c4d5e6f7a8b9c0d1e2" }

Activate Palette

Makes this palette the grade for one project, replacing whatever that project was using.

Endpoint

POST /api/v1/color-palettes/:id/activate

Request Body

ParameterTypeRequiredConstraint
projectIdstringYesMissing → 400 "Open a project to set its Color DNA". You must be the project owner or a member shared with edit or full permission, otherwise 403 — as is an id you cannot access or that does not exist.

The palette must belong to you or to another member of that project — a palette owned by someone outside the project returns 404.

Example

curl -X POST https://api.kolbo.ai/api/v1/color-palettes/66a2b3c4d5e6f7a8b9c0d1e2/activate \
  -H "X-API-Key: kolbo_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "projectId": "65f1c8a2e4b0a3c1d9f5e789" }'

Response

{
  "success": true,
  "color_palette": {
    "id": "66a2b3c4d5e6f7a8b9c0d1e2",
    "name": "Terracotta & Deep Navy",
    "colors": [{ "hex": "#E2725B", "name": "terracotta", "role": "dominant" }],
    "source_image_urls": [],
    "is_active": true,
    "content_scope": "personal",
    "created_at": "2026-06-02T10:11:12.000Z",
    "updated_at": "2026-06-02T10:11:12.000Z"
  }
}

Resolved palettes are cached in-process for 60 seconds, keyed by user and project, on each API worker. An activate, deactivate or delete can therefore take up to a minute to change what a generation is graded with — for you as well as for teammates in the same shared project.

Deactivate Palette

Clears a project's grade. Generations in that project stop being color-graded. The palette itself is untouched and stays in your library.

Endpoint

POST /api/v1/color-palettes/deactivate

Request Body

ParameterTypeRequiredConstraint
projectIdstringYesMissing → 400 "Open a project to set its Color DNA". You must be the project owner or a member shared with edit or full permission, otherwise 403 — as is an id you cannot access or that does not exist.

Example

curl -X POST https://api.kolbo.ai/api/v1/color-palettes/deactivate \
  -H "X-API-Key: kolbo_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "projectId": "65f1c8a2e4b0a3c1d9f5e789" }'

Response

{ "success": true }

Examples

Full flow: references → palette → graded generation

API_KEY="kolbo_live_..."
BASE="https://api.kolbo.ai/api/v1"
PROJECT="65f1c8a2e4b0a3c1d9f5e789"   # from GET /api/v1/projects

# 1. Extract colors from reference images (free, saves nothing)
curl -s -X POST "$BASE/color-palettes/analyze" \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{ "image_urls": ["https://cdn.kolbo.ai/uploads/ref1.jpg"] }'

# 2. Save the palette and grade the project with it in one call
curl -s -X POST "$BASE/color-palettes" \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d "{
    \"name\": \"Terracotta & Deep Navy\",
    \"colors\": [
      { \"hex\": \"#E2725B\", \"name\": \"terracotta\", \"role\": \"dominant\" },
      { \"hex\": \"#0F1E3D\", \"name\": \"deep navy\", \"role\": \"secondary\" }
    ],
    \"projectId\": \"$PROJECT\"
  }"

# 3. Every generation in that project is now graded
curl -s -X POST "$BASE/generate/image" \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d "{ \"prompt\": \"A coffee cup on a wooden table\", \"project_id\": \"$PROJECT\" }"

# 4. …unless you opt this one call out
curl -s -X POST "$BASE/generate/image" \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d "{ \"prompt\": \"Plain product cutout\", \"project_id\": \"$PROJECT\", \"skip_color_palette\": true }"

Stop grading a project

curl -X POST https://api.kolbo.ai/api/v1/color-palettes/deactivate \
  -H "X-API-Key: kolbo_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "projectId": "65f1c8a2e4b0a3c1d9f5e789" }'

Credits and Rate Limits

  • All Color Palette endpoints are free — no credits are charged, including analyze.
  • Shared bucket: 120 requests per minute per user across the SDK's media/asset endpoints.
  • POST /color-palettes/analyze has an additional dedicated limit of 10 requests per minute per user; exceeding it returns 429 with code RATE_LIMITED.