---
title: "Create (or upsert) a brand kit"
method: POST
path: "/v1/brand-kits"
tags: ["brand-kits"]
---

# Create (or upsert) a brand kit

`POST /v1/brand-kits`

## Request

- Base URL: `https://api.cueframe.ai`
- URL: `https://api.cueframe.ai/v1/brand-kits`
- Auth: one of:
  - HTTP bearer
  - OAuth 2 (authorization code, authorization URL `https://api.cueframe.ai/api/auth/mcp/authorize`, token URL `https://api.cueframe.ai/api/auth/mcp/token`, scopes: `projects:write`)
  - API key in header `PAYMENT-SIGNATURE`

Create or upsert a brand kit. Gated on the `brand_kits` boolean entitlement, which the FREE plan grants — brand-first authoring is deliberately never paywalled — so this is available to every account and costs no credits. A plan without it returns 402 billing_required (`details.featureId: "brand_kits"`). Discover the gate WITHOUT a failed round-trip via GET /v1/me — its `entitlements.brand_kits.included` tells you up front.

## Request body

- BrandKitCreateRequest: POST /brand-kits body. Org/user are server-resolved; never accepted from the body.
  - `kitId` string, required
  - `name` string, required
  - `description` string
  - `tagline` string
  - `secondaryTagline` string
  - `colors` object, required
    - `primary` string, required
    - `secondary` string, required
    - `accent` string, required
    - `background` string, required
    - `text` string, required
  - `extraColors` object[]
    - `hex` string, required
    - `label` string, required
    - `usage` string
  - `headingFont` object, required
    - `fontFamily` string, required
    - `fontWeight` number, required
  - `bodyFont` object, required
    - `fontFamily` string, required
    - `fontWeight` number, required
  - `voiceGuidelines` string
  - `syncCaptions` boolean
  - `captionProfile` object
    - `fontFamily` string
    - `fontSize` number
    - `fontWeight` number
    - `color` string
    - `highlightColor` string
    - `backgroundColor` string
    - `plate` 'glass' | 'solid' | 'none'
    - `position` 'top' | 'center' | 'bottom'
    - `textTransform` 'none' | 'uppercase'
    - `entrance` 'none' | 'fade' | 'word-pop' | 'stagger-up'
    - `entranceMs` number
    - `entranceStaggerMs` number
    - `exitMs` number
    - `emphasisColor` string
    - `emphasisScale` number
    - `emphasisFontFamily` string
    - `emphasisFontWeight` number
    - `emphasisFontStyle` 'normal' | 'italic'
    - `emphasisTextTransform` 'none' | 'uppercase'
    - `emphasisLetterSpacing` number
    - `emphasisPlate` boolean
    - `emphasisPlateColor` string
    - `emphasisPlateTextColor` string
  - `motion` object
    - `duration` number
    - `easing` union
      - 'linear' | 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out'
      - object
        - `kind` 'cubic-bezier', required
        - `x1` number, required
        - `y1` number, required
        - `x2` number, required
        - `y2` number, required
    - `entrance` 'none' | 'fade' | 'word-pop' | 'stagger-up'
    - `staggerMs` number
    - `exitMs` number
  - `logo` object
    - `src` string, required
    - `alt` string
    - `placement` 'tl' | 'tr' | 'bl' | 'br'
    - `sizePct` number
  - `intro` object
    - `kind` 'card' | 'video', required
    - `src` string
    - `title` string
    - `subtitle` string
    - `durationMs` number
  - `outro` object
    - `kind` 'card' | 'video', required
    - `src` string
    - `title` string
    - `subtitle` string
    - `durationMs` number
  - `watermark` object
    - `src` string, required
    - `opacity` number
    - `placement` 'tl' | 'tr' | 'bl' | 'br'
  - `spacing` object
    - `base` number
    - `lg` number
    - `sm` number
  - `sizing` object
    - `fontSizeHeading` number
    - `fontSizeBody` number
    - `fontSizeLabel` number
    - `borderRadius` number
  - `audio` object
    - `sfxIntensity` 'off' | 'light' | 'standard' | 'dense'
    - `musicEnabled` boolean
    - `musicMood` string
    - `sonicLogo` object: A brand sound signature bound to the intro/outro bookend. `ref` = a palette reference; bound only when the kit carries the matching bumper (intro/outro), else a non-blocking advisory.
      - `ref` string, required
      - `placement` 'intro' | 'outro' | 'both', required
      - `offsetMs` integer
    - `uiSoundSet` object: Per-family SFX overrides (the brand's own tick/pop/…). Highest-priority tier over the org palette + pack default in the compose SFX draw.
      - `tick` string
      - `pop` string
      - `impact` string
      - `confirm` string
      - `error` string
      - `whoosh` string
      - `riser` string
    - `bedStyle` object: Preferred music bed (`bedId`) or a style hint (`genre` / `bpmRange`). Surfaced for driving agents; compose does not auto-select a pack bed.
      - `bedId` string
      - `genre` string
      - `bpmRange` object
        - `min` number, required
        - `max` number, required
    - `ambiencePreference` object, nullable: Preferred ambience bed (`{ref}`) or explicit null (opt-out). Surfaced for driving agents; compose has no ambience auto-placement.
      - `ref` string, required
  - `exemplarKeys` string[]
  - `contactSheetKey` string
  - `motifs` object[]
    - `id` string, required
    - `observed` string, required
    - `body` union, required
      - object
        - `kind` 'card', required
        - `html` string, required
        - `tokens` object
      - object
        - `kind` 'overlay', required
        - `primitiveId` string, required
        - `params` object
      - object
        - `kind` 'component', required
        - `componentId` string, required
        - `props` object
    - `motion` object
      - `preset` 'fade-up' | 'slide-in-left' | 'slide-in-right' | 'scale-pop' | 'stagger-reveal', required
      - `enterMs` integer
      - `exitMs` integer
      - `staggerMs` integer
      - `confidence` 'high' | 'low'
    - `role` 'title-card' | 'stat' | 'lower-third' | 'pull-quote' | 'hero' | 'logo-tag' | 'enumeration' | 'sequence' | 'comparison', required
    - `zone` object
      - `x` number, required
      - `y` number, required
      - `w` number, required
      - `h` number, required
    - `evidence` integer[]
    - `diffScore` number
    - `coverage` 'reproduced' | 'approximated' | 'skipped', required
    - `skipReason` string
  - `styleRubric` string
  - `density` object
    - `graphicsPerMin` number, required
    - `maxSimultaneous` integer, required
  - `inspiration` object
    - `sources` string[], required
    - `extractedAt` number, required
    - `extractionVersion` string, required

## Response `201`

Brand kit created.

- BrandKitResponse: Brand kit response per §Brand Kits.
  - `id` string, required
  - `name` string, required
  - `description` string, nullable, required
  - `tagline` string, nullable, required
  - `colors` object, required
  - `extraColors` object[]
    - `name` string, required
    - `value` string, required
  - `fonts` object, required
    - `heading` object, nullable, required
      - `family` string, required
      - `weight` union
        - number
        - string
    - `body` object, nullable, required
      - `family` string, required
      - `weight` union
        - number
        - string
  - `voiceGuidelines` string, nullable, required
  - `captions` object, required
    - `sync` boolean, required
    - `profile` object, nullable, required
  - `motion` object
    - `duration` number
    - `easing` union
      - 'linear' | 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out'
      - object
        - `kind` 'cubic-bezier', required
        - `x1` number, required
        - `y1` number, required
        - `x2` number, required
        - `y2` number, required
    - `entrance` 'none' | 'fade' | 'word-pop' | 'stagger-up'
    - `staggerMs` number
    - `exitMs` number
  - `logo` object
    - `src` string, required
    - `alt` string
    - `placement` 'tl' | 'tr' | 'bl' | 'br'
    - `sizePct` number
  - `intro` object
    - `kind` 'card' | 'video', required
    - `src` string
    - `title` string
    - `subtitle` string
    - `durationMs` number
  - `outro` object
    - `kind` 'card' | 'video', required
    - `src` string
    - `title` string
    - `subtitle` string
    - `durationMs` number
  - `watermark` object
    - `src` string, required
    - `opacity` number
    - `placement` 'tl' | 'tr' | 'bl' | 'br'
  - `spacing` object
    - `base` number
    - `lg` number
    - `sm` number
  - `sizing` object
    - `fontSizeHeading` number
    - `fontSizeBody` number
    - `fontSizeLabel` number
    - `borderRadius` number
  - `audio` object
    - `sfxIntensity` 'off' | 'light' | 'standard' | 'dense'
    - `musicEnabled` boolean
    - `musicMood` string
    - `sonicLogo` object: A brand sound signature bound to the intro/outro bookend. `ref` = a palette reference; bound only when the kit carries the matching bumper (intro/outro), else a non-blocking advisory.
      - `ref` string, required
      - `placement` 'intro' | 'outro' | 'both', required
      - `offsetMs` integer
    - `uiSoundSet` object: Per-family SFX overrides (the brand's own tick/pop/…). Highest-priority tier over the org palette + pack default in the compose SFX draw.
      - `tick` string
      - `pop` string
      - `impact` string
      - `confirm` string
      - `error` string
      - `whoosh` string
      - `riser` string
    - `bedStyle` object: Preferred music bed (`bedId`) or a style hint (`genre` / `bpmRange`). Surfaced for driving agents; compose does not auto-select a pack bed.
      - `bedId` string
      - `genre` string
      - `bpmRange` object
        - `min` number, required
        - `max` number, required
    - `ambiencePreference` object, nullable: Preferred ambience bed (`{ref}`) or explicit null (opt-out). Surfaced for driving agents; compose has no ambience auto-placement.
      - `ref` string, required
  - `exemplarKeys` string[]
  - `contactSheetKey` string
  - `motifs` object[]
    - `id` string, required
    - `observed` string, required
    - `body` union, required
      - object
        - `kind` 'card', required
        - `html` string, required
        - `tokens` object
      - object
        - `kind` 'overlay', required
        - `primitiveId` string, required
        - `params` object
      - object
        - `kind` 'component', required
        - `componentId` string, required
        - `props` object
    - `motion` object
      - `preset` 'fade-up' | 'slide-in-left' | 'slide-in-right' | 'scale-pop' | 'stagger-reveal', required
      - `enterMs` integer
      - `exitMs` integer
      - `staggerMs` integer
      - `confidence` 'high' | 'low'
    - `role` 'title-card' | 'stat' | 'lower-third' | 'pull-quote' | 'hero' | 'logo-tag' | 'enumeration' | 'sequence' | 'comparison', required
    - `zone` object
      - `x` number, required
      - `y` number, required
      - `w` number, required
      - `h` number, required
    - `evidence` integer[]
    - `diffScore` number
    - `coverage` 'reproduced' | 'approximated' | 'skipped', required
    - `skipReason` string
  - `styleRubric` string
  - `density` object
    - `graphicsPerMin` number, required
    - `maxSimultaneous` integer, required
  - `inspiration` object
    - `sources` string[], required
    - `extractedAt` number, required
    - `extractionVersion` string, required
  - `createdAt` string, required
  - `updatedAt` string, required

## Other responses

- `400`: Bad request — validation_error / invalid_cursor / invalid_query.
- `401`: Missing or invalid Authorization header.
- `402`: Payment required — billing_required or x402 payment_*.
- `403`: Forbidden — permission insufficient.
- `422`: Unprocessable — invalid_composition / media_in_use / session_in_use / render_not_cancellable.
- `429`: Rate limited. Retry-After header present.
- `500`: Internal error.

---

[API](https://skmtc.dev/cueframe/apis/cueframe-api.md) · [All operations](https://skmtc.dev/cueframe/apis/cueframe-api/llms.txt) · [OpenAPI document](https://skmtc.dev/cueframe/apis/cueframe-api/revisions/8f9bfe362b4a?raw)
