Color Palettes
Color DNA — save a palette and strict-grade every graded generation on your account 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 your account: a plain-language directive ("dominant terracotta, secondary deep navy, accent warm gold…") is woven into the prompt of every graded generation you make, 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.
Color DNA is sticky and account-wide. One palette is active per account at a time, and it
grades every graded generation in every project — whatever project_id the generation is
sent with — until you deactivate it or activate a different one. Activating a palette needs no
project. A projectId on create/activate is optional and only files the palette under that
project (see below); it never limits the grade to that project.
Where the grade is applied
| Endpoint | Graded | Per-request opt-out |
|---|---|---|
POST /api/v1/generate/image | Yes | skip_color_palette: true |
POST /api/v1/generate/image-edit | Yes | skip_color_palette: true |
POST /api/v1/generate/video (text-to-video) | Yes — unless auto-routed to image-to-video (see below) | skip_color_palette: true |
POST /api/v1/generate/creative-director | Yes (all scenes) | none — the endpoint does not accept skip_color_palette |
POST /api/v1/generate/video/from-image | No | skip_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 active palette, and
skip_color_palette there is a no-op. The same applies when you send a reference_images
entry to POST /generate/video: the SDK delegates that request to the model's image-to-video
sibling, so it is not graded either.
Every other generation endpoint (Elements, first/last frame, video-to-video, lipsync, 3D,
speech, sound, music, chat) 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/deactivateWhere a project id is accepted, both projectId and project_id work (if you send
both, projectId wins). List (query string), create and activate (body) read it; deactivate
accepts and ignores it. Update, delete and analyze have no project parameter — and because the
create/update bodies are validated strictly, sending projectId, project_id or any other
unlisted field 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": "…", "message": "…", "limit": 120, "window_seconds": 60, "retryAfter": …}
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 to your active organization, newest
first, and — separately and unpaginated — Kolbo's built-in system presets. is_active marks the
palette that is currently your account's Color DNA, wherever it appears.
When a project id is supplied and you can access the project, the list also includes the palette
that project has filed as its own (even if a teammate owns it), and — if you are the owner or an
edit/full member — every palette created in that project by any member.
Endpoint
GET /api/v1/color-palettesQuery Parameters
| Parameter | Type | Required | Constraint |
|---|---|---|---|
projectId / project_id | string | No | Project id. Adds that project's palettes to the list as described above. It does not affect is_active, which is account-wide. An invalid or inaccessible id is ignored, not an error. |
page | integer | No | Default 1. Clamped to a minimum of 1. |
limit | integer | No | Default 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"
}
],
"presets": [
{
"id": "66a2b3c4d5e6f7a8b9c0d0aa",
"name": "Example Preset",
"colors": [{ "hex": "#E8C170", "name": "warm gold", "role": "dominant" }],
"source_image_urls": [],
"is_active": false,
"content_scope": "system",
"created_at": "2026-05-01T00:00:00.000Z",
"updated_at": "2026-05-01T00:00:00.000Z"
}
],
"pagination": { "page": 1, "limit": 50, "total": 1, "pages": 1 }
}pagination covers color_palettes only; presets is always returned in full.
content_scope is "personal", "organization" or (in presets) "system". A palette you
create is "personal" unless you create it with shareWithOrganization: true. Update and delete
match on ownership, so they work on palettes you own (personal or shared to your organization)
and return 404 for everything else — teammates' palettes, organization palettes published by an
org admin, and system presets. Activate is broader: you can activate system presets and your
active organization's palettes directly.
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/analyzeRequest Body
| Parameter | Type | Required | Constraint |
|---|---|---|---|
image_urls | string[] | Yes | 1-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 or decoded are skipped; if none of them can be used the request
returns 400 with "Failed to download any images". 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"; a non-string entry returns
"Each imageUrl must be a string". 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-palettesRequest Body
| Parameter | Type | Required | Constraint |
|---|---|---|---|
name | string | Yes | 1-100 characters after trimming. |
colors | object[] | Yes | 1-10 entries. See the color object below. |
source_image_urls | string[] | No | Max 5 entries, each a valid URI. Stored as provenance only. A 6th entry is a 400. |
is_active | boolean | No | Default true: the new palette immediately becomes your account's Color DNA, replacing the previously active one. Send false to save it without activating — only the JSON literal false skips activation; the string "false" passes validation but still activates. |
projectId / project_id | string | No | Project to file the palette under. Applied only when you are the project owner or an edit/full member: the palette is recorded as created in that project (so the project's edit/full members see it when they list with that project id) and, when it is also activated, becomes the project's own palette. An invalid, inaccessible or read-only id is silently ignored — no error. It never limits the grade to that project. |
shareWithOrganization | boolean | No | Default false. true publishes the palette to your active organization (content_scope: "organization") so its members see it in their list. Ignored when you have no active organization. |
Color object:
| Field | Type | Required | Constraint |
|---|---|---|---|
hex | string | Yes | #RRGGBB, exactly 6 hex digits. |
name | string | No | Up 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. |
role | string | No | dominant | secondary | accent | background. Stored default is accent, so responses always carry a role even when you omit it. |
Creating a palette activates it by default — from then on every graded generation on your
account is graded with it. Send "is_active": false when you only want to store a palette.
A successful create returns HTTP 201.
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" }
]
}'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/:idRequest Body
| Parameter | Type | Required | Constraint |
|---|---|---|---|
name | string | No | 1-100 characters after trimming. |
colors | object[] | No | 1-10 entries, same object shape as create. Full replacement — omit to keep the current colors. |
source_image_urls | string[] | No | Max 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": true,
"content_scope": "personal",
"created_at": "2026-06-02T10:11:12.000Z",
"updated_at": "2026-06-02T12:30:00.000Z"
}
}is_active here is the palette's stored flag: true when this palette is your account's active
Color DNA. Updating the active palette changes the grade in place (subject to the cache described
under Activate) — no re-activation needed.
Delete Palette
Owner only (404 otherwise). If this palette was your account's active Color DNA, Color DNA is
turned off and your generations go back to ungraded. Any project that had filed it as its own
palette has that reference cleared.
Endpoint
DELETE /api/v1/color-palettes/:idExample
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 your account's Color DNA, replacing whichever palette was active. The body is optional — an empty body is valid.
Endpoint
POST /api/v1/color-palettes/:id/activateRequest Body
| Parameter | Type | Required | Constraint |
|---|---|---|---|
projectId / project_id | string | No | When you are the project owner or an edit/full member, the palette also becomes that project's own palette, and you may activate a palette owned by another member of that project. An invalid, inaccessible or read-only id is silently ignored. |
You can activate a palette you own, any system preset (presets in the list response), any
palette shared to your active organization, or — with a writable projectId — a palette owned
by a member of that project. Anything else returns 404 "Color palette not found or access
denied".
Example
curl -X POST https://api.kolbo.ai/api/v1/color-palettes/66a2b3c4d5e6f7a8b9c0d1e2/activate \
-H "X-API-Key: kolbo_live_..."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"
}
}The active palette is cached in-process for 60 seconds per user on each API worker. The worker that handles a create, update, delete, activate or deactivate drops its cache immediately, but other workers can keep grading with the previous palette for up to a minute.
Deactivate Palette
Turns Color DNA off for your account. Your generations stop being color-graded in every project, and the project-palette reference is cleared on every project you own. The palette itself is untouched and stays in your library.
Endpoint
POST /api/v1/color-palettes/deactivateRequest Body
None. A projectId / project_id is accepted for backward compatibility and ignored.
Example
curl -X POST https://api.kolbo.ai/api/v1/color-palettes/deactivate \
-H "X-API-Key: kolbo_live_..."Response
{ "success": true }Examples
Full flow: references → palette → graded generation
API_KEY="kolbo_live_..."
BASE="https://api.kolbo.ai/api/v1"
# 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 - it becomes your account's active Color DNA in the same 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" }
]
}'
# 3. Every graded generation is now graded, in any project
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" }'
# 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", "skip_color_palette": true }'Turn Color DNA off
curl -X POST https://api.kolbo.ai/api/v1/color-palettes/deactivate \
-H "X-API-Key: kolbo_live_..."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. Requests that fail (4xx/5xx) are not counted against it.
POST /color-palettes/analyzehas an additional dedicated limit of 10 requests per minute per user; exceeding it returns429with codeRATE_LIMITED.
Related
Image Generation
Generate images; opt out per call with skip_color_palette
Image Editing
Edits are graded by your active palette too
Video Generation
Text-to-video is graded; image-to-video is not
Projects
Find a project id to file a palette under
Moodboards
Style templates — combine with a palette for color plus aesthetic
Cinematic Presets
Camera, lens, and lighting treatment on top of the grade