> ## Documentation Index
> Fetch the complete documentation index at: https://heygen-1fa696a7.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Brand Kits

> Create a brand kit over the API by importing a website's colors, fonts, and logos, then pass its brand_kit_id to Video Agent so every generated video ships on-brand.

<img className="w-full h-44 object-cover rounded-xl" src="https://mintcdn.com/heygen-1fa696a7/hfMXXwJzjE7vBSYZ/images/theme/research.webp?fit=max&auto=format&n=hfMXXwJzjE7vBSYZ&q=85&s=3e4c2594813dcfd56985f3d63e3ba321" alt="" noZoom width="1400" height="788" data-path="images/theme/research.webp" />

A brand kit is a saved set of brand colors, fonts, and logos. Pass its `brand_kit_id` to the [Video Agent](/docs/video-agent) and the agent applies it to everything it builds — scene backgrounds, text treatments, chart palettes, and logo placement — so output ships on-brand without describing your brand in the prompt.

You can build a kit two ways: author it in the HeyGen app under **Brand Kit**, or import one from a public website over the API. Either way you end up with a `brand_kit_id`, and a kit created over the API stays editable in the app.

A brand kit governs how a video **looks**. To control how your terms are **spoken**, pair it with a [brand glossary](/docs/brand-glossary) on the endpoints that accept one — see [On Brand](/docs/on-brand).

<Info>
  **API reference:** [Create Brand Kit](/reference/create-brand-kit) · [Get Brand Kit](/reference/get-brand-kit) · [List Brand Kits](/reference/list-brand-kits) · [Create Session](/reference/create-video-agent-session) · [Send Message](/reference/send-message-or-request-revision)
</Info>

## Import a kit from a website

[`POST /v3/brand-kits`](/reference/create-brand-kit) visits a public URL, imports the logos, colors, and font files it finds there, and assembles them into a kit. This is the path to on-brand output for a workspace that has never opened the HeyGen app — onboard a customer by their own domain and generate their first branded video in the same run.

<Note>
  By calling this endpoint you confirm you have the rights and licenses necessary to upload, store, and use the imported assets in HeyGen.
</Note>

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST "https://api.heygen.com/v3/brand-kits" \
    -H "X-Api-Key: $HEYGEN_API_KEY" \
    -H "Content-Type: application/json" \
    -H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
    -d '{
      "url": "https://www.acme.com",
      "name": "Acme Corp — Primary"
    }'
  ```

  ```python Python theme={null}
  import requests, uuid

  resp = requests.post(
      "https://api.heygen.com/v3/brand-kits",
      headers={
          "X-Api-Key": HEYGEN_API_KEY,
          "Idempotency-Key": str(uuid.uuid4()),
      },
      json={"url": "https://www.acme.com", "name": "Acme Corp — Primary"},
  )
  brand_kit_id = resp.json()["data"]["brand_kit_id"]
  ```

  ```javascript Node.js theme={null}
  const resp = await fetch("https://api.heygen.com/v3/brand-kits", {
    method: "POST",
    headers: {
      "X-Api-Key": process.env.HEYGEN_API_KEY,
      "Content-Type": "application/json",
      "Idempotency-Key": crypto.randomUUID(),
    },
    body: JSON.stringify({ url: "https://www.acme.com", name: "Acme Corp — Primary" }),
  });
  const { data } = await resp.json();
  ```
</CodeGroup>

| Parameter | Type   | Required | Description                                                                                             |
| --------- | ------ | -------- | ------------------------------------------------------------------------------------------------------- |
| `url`     | string | Yes      | Public website URL to build the kit from, up to 2048 characters.                                        |
| `name`    | string | No       | Name for the kit, up to 256 characters. Defaults to the brand name detected on the site, or its domain. |

Send an `Idempotency-Key` header so a retry is free: a repeat within 24 hours replays the original response instead of starting a second import of the same site. A retry that arrives while the first request is still in flight gets a `409` with code `request_in_progress` — wait a moment and try again.

`201` comes back as soon as the kit record exists, before any asset has been imported:

```json theme={null}
{
  "data": {
    "brand_kit_id": "3f9a1c47b8e24d5fa0c61e8b7d24f6a1",
    "status": "loading"
  }
}
```

The `brand_kit_id` is usable immediately, including on a Video Agent request. The assets behind it are gathered in the background.

## Read a kit and wait for the import

[`GET /v3/brand-kits/{brand_kit_id}`](/reference/get-brand-kit) returns one kit with its colors, logos, and fonts, and which of them plays which role. After an import, poll it every 2 to 5 seconds until `status` is `completed` and read the palette only then. A website import usually settles in under two minutes; fonts are typically the last thing to land, so a kit that already has colors and a logo may still be `loading`.

```bash theme={null}
curl "https://api.heygen.com/v3/brand-kits/3f9a1c47b8e24d5fa0c61e8b7d24f6a1" \
  -H "X-Api-Key: $HEYGEN_API_KEY"
```

```json theme={null}
{
  "data": {
    "brand_kit_id": "3f9a1c47b8e24d5fa0c61e8b7d24f6a1",
    "name": "Acme Corp — Primary",
    "status": "completed",
    "colors": ["#FF5733", "#1A1A1A", "#FFFFFF"],
    "color_roles": {
      "primary": "#FF5733",
      "secondary": "#1A1A1A",
      "tertiary": "#F4F1EC",
      "accent": "#FFB400"
    },
    "logos": [
      {
        "logo_id": "c4e18a72f95b4d6e8a30b7c15d92f6e3",
        "name": "Acme wordmark",
        "url": "https://resource2.heygen.ai/image/c4e18a72f95b4d6e8a30b7c15d92f6e3/original"
      }
    ],
    "logo_roles": { "primary": "c4e18a72f95b4d6e8a30b7c15d92f6e3" },
    "fonts": [{ "font_id": "9d7b2f6c14a84e0b9c53d81f2a67b405", "name": "Inter" }],
    "font_roles": {
      "title_text": { "font_id": "9d7b2f6c14a84e0b9c53d81f2a67b405", "weight": 700 },
      "body_text": { "font_id": "9d7b2f6c14a84e0b9c53d81f2a67b405", "weight": 400 }
    }
  }
}
```

| Field         | Type           | Description                                                                                                                           |
| ------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `status`      | string         | `loading` while the kit is still being built, `completed` once the import has finished contributing, or `error` if the import failed. |
| `colors`      | array          | Brand colors as hex values.                                                                                                           |
| `color_roles` | object \| null | Which color is `primary`, `secondary`, `tertiary`, and `accent`.                                                                      |
| `logos`       | array          | Logos in the kit, each with a `logo_id`, `name`, and `url`.                                                                           |
| `logo_roles`  | object         | Names the `logo_id` of the brand's main logo as `primary`.                                                                            |
| `fonts`       | array          | Fonts in the kit, each with a `font_id` and family `name`.                                                                            |
| `font_roles`  | object \| null | Which font and `weight` carry `title_text` and `body_text`.                                                                           |

### Reading roles safely

Two habits keep a kit reader robust once a human starts editing the kit in the app:

* **A role can name a color outside `colors`.** The palette lists the brand's core swatches, while a role such as `tertiary` may point at a supporting surface color that isn't one of them. Read `color_roles` for roles and `colors` for the palette rather than deriving one from the other.
* **A role can name an asset that no longer exists.** Deleting a logo or font leaves the role that referenced it in place, so look the `logo_id` or `font_id` up in `logos` or `fonts` and handle the miss instead of assuming the lookup succeeds.

Both collections and the role fields are provisional while `status` is `loading`, which is the other reason to wait for `completed`.

`status` is `error` when the import failed. The kit still exists and keeps whatever was assembled before the failure, so it remains usable — check `colors`, `logos`, and `fonts` to see what made it through, and fill the gaps in the HeyGen app. `completed` means the import is done, not that the kit is frozen.

## List your brand kits

[`GET /v3/brand-kits`](/reference/list-brand-kits) returns the kits available in the authenticated workspace — the endpoint to reach for when you need an ID for a kit somebody else created in the app.

| Parameter | Type    | Default | Description                                            |
| --------- | ------- | ------- | ------------------------------------------------------ |
| `limit`   | integer | 20      | Results per page, 1–100.                               |
| `token`   | string  | —       | Opaque cursor from a previous response's `next_token`. |

```bash theme={null}
curl "https://api.heygen.com/v3/brand-kits" \
  -H "X-Api-Key: $HEYGEN_API_KEY"
```

```json theme={null}
{
  "data": [
    {
      "brand_kit_id": "3f9a1c47b8e24d5fa0c61e8b7d24f6a1",
      "name": "Acme Corp — Primary",
      "logo_url": "https://resource2.heygen.ai/image/c4e18a72f95b4d6e8a30b7c15d92f6e3/original",
      "colors": ["#FF5733", "#1A1A1A", "#FFFFFF"]
    }
  ],
  "has_more": false,
  "next_token": null
}
```

The listing is a summary: it carries `logo_url` for the primary logo and the color list, but not fonts or role assignments. Read a kit by ID when you need those.

<Note>
  `logo_url` is `null` when a kit defines colors and fonts but no logo, which is common — treat it as optional rather than assuming a logo is present.
</Note>

## Apply a brand kit to a video

Pass `brand_kit_id` when you create the session. It works in both `generate` and `chat` modes.

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST "https://api.heygen.com/v3/video-agents" \
    -H "X-Api-Key: $HEYGEN_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "prompt": "Create a 45-second explainer about our Q3 product launch.",
      "brand_kit_id": "3f9a1c47b8e24d5fa0c61e8b7d24f6a1",
      "orientation": "landscape"
    }'
  ```

  ```python Python theme={null}
  import requests

  resp = requests.post(
      "https://api.heygen.com/v3/video-agents",
      headers={"X-Api-Key": HEYGEN_API_KEY},
      json={
          "prompt": "Create a 45-second explainer about our Q3 product launch.",
          "brand_kit_id": "3f9a1c47b8e24d5fa0c61e8b7d24f6a1",
          "orientation": "landscape",
      },
  )
  session_id = resp.json()["data"]["session_id"]
  ```

  ```javascript Node.js theme={null}
  const resp = await fetch("https://api.heygen.com/v3/video-agents", {
    method: "POST",
    headers: {
      "X-Api-Key": process.env.HEYGEN_API_KEY,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      prompt: "Create a 45-second explainer about our Q3 product launch.",
      brand_kit_id: "3f9a1c47b8e24d5fa0c61e8b7d24f6a1",
      orientation: "landscape",
    }),
  });
  const { data } = await resp.json();
  ```
</CodeGroup>

### Switch brands mid-session

In an [interactive session](/docs/interactive-sessions), `brand_kit_id` is also accepted on each follow-up message, so you can re-brand without starting over — useful when producing the same video for multiple brands or sub-brands.

```bash theme={null}
curl -X POST "https://api.heygen.com/v3/video-agents/sess_abc123" \
  -H "X-Api-Key: $HEYGEN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "message": "Rebuild this with our EMEA sub-brand.",
    "brand_kit_id": "7b41e05c9d3a4e628fb15c2a6d80e39f"
  }'
```

### Brand kits and styles

`brand_kit_id` and `style_id` are independent and can be combined:

* **`style_id`** picks a curated visual template — scene layout, pacing, overall aesthetic. See [Styles & References](/docs/styles-and-references).
* **`brand_kit_id`** supplies your colors, fonts, and logo.

Use a style for the look of the video and a brand kit to make that look yours.

## Errors

| Status | Code                  | Meaning                                                                                                             |
| ------ | --------------------- | ------------------------------------------------------------------------------------------------------------------- |
| `400`  | `invalid_parameter`   | The URL could not be imported — `"URL is not supported"`. Check that it is a public page reachable without a login. |
| `403`  | `forbidden`           | Your workspace settings do not allow creating brand kits.                                                           |
| `404`  | `resource_not_found`  | No brand kit with that ID in the authenticated workspace.                                                           |
| `409`  | `request_in_progress` | A request with this `Idempotency-Key` is still running. Retry shortly.                                              |
| `429`  | `rate_limit_exceeded` | Retry after the duration in the `Retry-After` header.                                                               |

An unknown or inaccessible `brand_kit_id` on a Video Agent request is rejected when the request is made, rather than failing partway through the render:

```json theme={null}
{
  "error": {
    "code": "resource_not_found",
    "message": "Brand kit not found.",
    "param": "brand_kit_id",
    "doc_url": null
  }
}
```

Brand kits are scoped to the authenticated workspace. If you get this error with an ID that exists, confirm the API key belongs to the same workspace that owns the brand kit.
