# Get brand dependents

> GET /v1/brands/{id}/dependents · Core resources API

Source: https://developer.kustomer.com/api/core-resources/get-brand-dependents

```http
GET https://{orgname}.api.kustomerapp.com/v1/brands/{id}/dependents
Authorization: Bearer <API key>
```

## Authorization

Requires any one of these roles: `org.permission.brand.read`; or legacy `org.admin.brand.read`, `org.user.brand.read`. The API key or user must hold at least one of them. Legacy roles predate permission sets and still work.

Lists what prevents a brand from being deleted, so you can check before calling [Delete brand](ref:deletebrand). The result is advisory: Delete brand re-checks everything and returns `409` if a blocker has appeared since, so always handle that response. That re-check is not transactional either: a dependent created at the same moment as the delete can still slip through.

`data.deletable` is `true` only when both `blockers` and `unknown` are empty. A check that could not run (error or timeout) is listed in `unknown` and keeps `deletable` `false`; call the endpoint again to retry. Do not cache the response.

Each blocker has a stable `reason` code. New codes can be added over time, so treat an unrecognized `reason` as "something still uses this brand".

|reason|type|Blocks when|
|-----|-----|-----|
|default_brand|brand|The brand is the default brand. It can never be deleted.|
|knowledge_base|knowledge_base|Any knowledge base is attached to the brand, even one with no published articles.|
|brand_address|brand_address|At least one email address is routed to the brand.|
|chat_settings_active|chat_settings|The brand's chat settings name an assistant that is in use.|
|assistant_default_assigned|assistant_settings|An assistant that is in use is the brand's default on at least one channel.|
|assistant_rule_brand_criteria|assistant_rule|An enabled assistant rule has a brand condition naming the brand and runs an assistant that is in use.|
|assistant_automation_brand_criteria|assistant_automation|An active AI automation is bound to the brand through an enabled business rule.|

An assistant is "in use" when it is not deleted and a version of it is active. Draft, unpublished and system-disabled assistants do not block.

## About Brands

A brand represents one of the companies, products or storefronts you support from a single Kustomer org. Brands let each one have its own name and icon, chat widget settings, knowledge base and email addresses.

Many businesses run more than one brand out of one support team, for example a retailer with two storefronts. In Kustomer each of these is a brand. Admins manage brands in the admin settings, and other configuration hangs off them: chat settings (colors, greeting, business hours and assistant) are set per brand, each knowledge base belongs to a brand, and the web chat SDK takes a `brandId` to choose which brand's widget to load. Every org starts with one brand, created when the org is registered and marked `default: true`. Chat uses the default brand when it starts without a `brandId`.

#### Brand fields

A brand is small: `name` and `iconUrl` are the only fields you write, and both are required when you create or update one. `default` tells you whether it's the org's default brand. `deleted` and `deletedAt` say whether and when the brand was deleted.

#### Deleting a brand

[`DELETE /v1/brands/{id}`](https://developer.kustomer.com/api/core-resources/delete-brand) is a soft delete. The brand is flagged `deleted: true` with a `deletedAt` time and kept, so conversations and reports that point to it can still resolve its name. It returns `204` with no body. It needs brand write permission or the brand delete permission. There's no way to restore a deleted brand, and `PATCH` on it returns `404`.

Kustomer won't delete a brand that's still in use. Call [`GET /v1/brands/{id}/dependents`](https://developer.kustomer.com/api/core-resources/get-brand-dependents) first. It returns `deletable` with two lists: `blockers`, which says what's in the way, and `unknown`, which lists what couldn't be checked. These block a delete:

- Being the org's default brand. The default can never be deleted.
- Any knowledge base for the brand, published or not
- Any brand address mapping. Remove them with [`DELETE /v1/brandAddresses/brand/{brandId}`](https://developer.kustomer.com/api/core-resources/delete-all-mappings-for-a-brand).
- Chat settings with an active assistant, or an active assistant that's the default for a channel
- An enabled assistant rule, or an enabled rule that runs an AI automation, whose criteria name the brand

When the delete is refused you get `409 conflict` with `source.parameter` set to `id`, and `detail` tells you which case it is:

| `detail` | `meta` | What to do |
| --- | --- | --- |
| `Cannot delete the default brand` | None | Nothing. The default brand can't be deleted. |
| `Cannot delete a brand that has dependents` | `blockers` lists what's in the way, and `unknown` lists any types that couldn't be checked | Remove or reassign each blocker, then try again |
| `Cannot delete a brand while its dependents cannot be checked` | `blockers` is empty, and `unknown` lists the types that couldn't be checked | Retry later |

The check fails closed: if any dependent type can't be checked within a few seconds, the brand isn't deleted. It also isn't atomic with the delete, so something created at the same moment can be missed.

The other errors from the delete:

| Status | When |
| --- | --- |
| `400 badparam` | `id` isn't a valid ID |
| `401 unauthorized` | The token is missing or invalid, or lacks `org.admin.brand.write` or `org.permission.brand.delete`. For a missing role, `source.parameter` is `roles` and `detail` lists the roles that would work. |
| `404 notfound` | No brand with this ID in your org, or it's already deleted |
| `429 too_many_requests` | Over the org or user [rate limit](https://developer.kustomer.com/docs/concepts/rate-limits). Brands have no limit of their own. Retry after `x-ratelimit-reset`. |

After a delete:

- [`GET /v1/brands`](https://developer.kustomer.com/api/core-resources/get-brands) and [`GET /v1/brands/{id}`](https://developer.kustomer.com/api/core-resources/get-brand-by-id) leave the brand out, or return `404` for it by ID. Pass `includeDeleted=true` to get it back, for example to show the name of a deleted brand on old conversations. [`GET /v1/brands/default`](https://developer.kustomer.com/api/core-resources/get-default-brand) is unaffected, because the default can't be deleted.
- Existing conversations keep their `brand` ID and can still be updated. Creating a conversation with a deleted or unknown `brand` ID returns `400 badparam` with `detail` set to `Brand not found or deleted` and `source.parameter` set to `brand`. See [`POST /v1/conversations`](https://developer.kustomer.com/api/core-resources/create-conversation).
- `PATCH /v1/brands/{id}` on the deleted brand returns `404`, the same as for an ID that doesn't exist.
- Kustomer cleans up settings tied to the brand in the background, after the `204`, and retries if a cleanup step fails. The cleanup starts from an event that's sent after the delete is saved, so in rare cases where that event can't be sent, the delete still succeeds but the cleanup doesn't run. PubNub keysets linked to the brand are unlinked from it and disabled. Brand-specific AI customization profiles (not the org default) are deleted with their tasks. A Shopify store whose storefront chat used the brand has its chat brand cleared, which turns the storefront chat widget off.

A `5xx` from the delete doesn't always mean nothing happened: the brand can be deleted even though the response failed. Check with `GET /v1/brands/{id}?includeDeleted=true` before you retry, since deleting an already deleted brand returns `404`.

#### Brand address mappings

A brand address mapping links an email address to a brand, so Kustomer knows which brand an address belongs to. One address can be mapped to several brands, and each brand can mark at most one of its mapped addresses with `isDefault: true`. Addresses are matched case-insensitively.

These endpoints behave differently from most write endpoints:

- `POST /v1/brandAddresses` is idempotent. Posting an address and brand pair that already exists returns the existing mapping with `200` instead of creating a duplicate. A new mapping returns `201`.
- `POST` accepts an optional `allBrands` flag. When `true`, the address is shared across every brand, and Kustomer syncs the flag onto every mapping for that address. If you leave it out on create and another mapping for the same address is already shared, the new mapping inherits `true`.
- `PATCH` changes only `isDefault` and `allBrands`, and needs at least one of them. Setting `isDefault` to `true` moves the default from the brand's previous default address. Deleting the default mapping leaves the brand with no default; Kustomer doesn't promote another address automatically.
- Deleting all mappings for an address first checks whether the address is still connected to an email account in Kustomer. If it is, nothing is deleted and the response reports `live: true`. If Kustomer can't confirm either way, it deletes nothing and returns `503`.

#### Which endpoint to use

| To | Call |
| --- | --- |
| List brands, for example to find a `brandId` for chat | [`GET /v1/brands`](https://developer.kustomer.com/api/core-resources/get-brands) |
| Get the org's default brand | [`GET /v1/brands/default`](https://developer.kustomer.com/api/core-resources/get-default-brand) |
| Create, read or update a brand | [`POST /v1/brands`](https://developer.kustomer.com/api/core-resources/create-brand), [`GET`](https://developer.kustomer.com/api/core-resources/get-brand-by-id) or [`PATCH /v1/brands/{id}`](https://developer.kustomer.com/api/core-resources/update-brand) |
| See what stops a brand from being deleted | [`GET /v1/brands/{id}/dependents`](https://developer.kustomer.com/api/core-resources/get-brand-dependents) |
| Delete a brand | [`DELETE /v1/brands/{id}`](https://developer.kustomer.com/api/core-resources/delete-brand) |
| Include deleted brands in a read | `includeDeleted=true` on [`GET /v1/brands`](https://developer.kustomer.com/api/core-resources/get-brands) or [`GET /v1/brands/{id}`](https://developer.kustomer.com/api/core-resources/get-brand-by-id) |
| See which brands an email address is mapped to | [`GET /v1/brandAddresses`](https://developer.kustomer.com/api/core-resources/list-brand-address-mappings), with `address` to look up one address |
| Map an address to a brand | [`POST /v1/brandAddresses`](https://developer.kustomer.com/api/core-resources/create-brand-address-mapping) |
| Make a mapped address the brand's default, or clear it | [`PATCH /v1/brandAddresses/{id}`](https://developer.kustomer.com/api/core-resources/update-brand-address-mapping) |
| Remove one mapping | [`DELETE /v1/brandAddresses/{id}`](https://developer.kustomer.com/api/core-resources/delete-brand-address-mapping-by-id) |
| Remove every mapping for an address, or for a brand | [`DELETE /v1/brandAddresses/address/{address}`](https://developer.kustomer.com/api/core-resources/delete-all-mappings-for-an-address) or [`DELETE /v1/brandAddresses/brand/{brandId}`](https://developer.kustomer.com/api/core-resources/delete-all-mappings-for-a-brand) |

Brand reads, including the dependents check, are available to most users. Writing brands needs brand write permission, deleting one needs brand write or the brand delete permission, and brand address mappings use the apps permissions. A brand can have only one default address at a time, so if two requests try to set different defaults for the same brand at once, one of them can fail with `409 Conflict`. Read the mappings again and retry.

Related: [Chat settings](https://developer.kustomer.com/api/settings-and-configurations#chat-settings), [Knowledge bases](https://developer.kustomer.com/api/knowledge-base#knowledge-bases), [Web chat](https://developer.kustomer.com/docs/chat/web)

### Recipes

#### 1. Load the right chat widget on each storefront

Look up each brand's ID so every site you run opens chat with its own brand's settings and knowledge base.

**Step 1.** [`GET /v1/brands`](https://developer.kustomer.com/api/core-resources/get-brands.md). List the brands and note each one's ID. The brand with `default: true` is the one chat falls back to.

```bash title="cURL"
curl "https://api.kustomerapp.com/v1/brands" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY"
```

```bash title="kusty (coming soon)"
kusty api GET /v1/brands --all \
  | jq -r '[.data.id, .data.attributes.name, .data.attributes.default] | @tsv'
```

**Step 2.** Pass the brand's ID as `brandId` when you start the [web chat SDK](https://developer.kustomer.com/docs/chat/web) on that storefront. Without it, chat loads the default brand.

```js
Kustomer.start({ brandId: 'YOUR_BRAND_ID' })
```

#### 2. Map support addresses to a brand

Tell Kustomer which email addresses belong to a brand, for example when you add a new storefront with its own support inbox.

**Step 1.** [`GET /v1/brands`](https://developer.kustomer.com/api/core-resources/get-brands.md). Find the brand's ID by name.

```bash title="cURL"
curl "https://api.kustomerapp.com/v1/brands" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY"
```

```bash title="kusty (coming soon)"
BRAND_ID=$(kusty api GET /v1/brands --all \
  | jq -r 'select(.data.attributes.name == "Kustom Socks") | .data.id')
```

**Step 2.** [`POST /v1/brandAddresses`](https://developer.kustomer.com/api/core-resources/create-brand-address-mapping.md). Map each address. The call is idempotent: if the address and brand are already mapped, you get the existing mapping back with `200` instead of a duplicate, so it's safe to run from a setup script.

```bash title="cURL"
curl --request POST "https://api.kustomerapp.com/v1/brandAddresses" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY" \
  --header "Content-Type: application/json" \
  --data "{\"address\": \"support@kustomsocks.com\", \"brand\": \"$BRAND_ID\"}"
```

```bash title="kusty (coming soon)"
for address in support@kustomsocks.com returns@kustomsocks.com; do
  kusty api POST /v1/brandAddresses --field address=$address --field brand=$BRAND_ID --fields id
done
```

**Step 3.** [`PATCH /v1/brandAddresses/{id}`](https://developer.kustomer.com/api/core-resources/update-brand-address-mapping.md). Make the main address the brand's default. The previous default for the brand stops being the default. If another request sets a default for the same brand at the same moment, this can fail with `409 Conflict`; read the mappings again and retry.

```bash title="cURL"
curl --request PATCH "https://api.kustomerapp.com/v1/brandAddresses/$MAPPING_ID" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{"isDefault": true}'
```

```bash title="kusty (coming soon)"
kusty api PATCH /v1/brandAddresses/$MAPPING_ID --field isDefault:=true
```

#### 3. Retire a support address

Remove an old email address from every brand it's mapped to, after it's no longer used to send or receive mail.

**Step 1.** [`GET /v1/brandAddresses`](https://developer.kustomer.com/api/core-resources/list-brand-address-mappings.md). Check which brands the address is mapped to, and whether it's any brand's default. Removing a default mapping leaves that brand with no default address until you set another.

```bash title="cURL"
curl "https://api.kustomerapp.com/v1/brandAddresses?address=help@oldbrand.com" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY"
```

```bash title="kusty (coming soon)"
kusty api GET /v1/brandAddresses --query address=help@oldbrand.com --all
```

**Step 2.** [`DELETE /v1/brandAddresses/address/{address}`](https://developer.kustomer.com/api/core-resources/delete-all-mappings-for-an-address.md). Delete every mapping for the address in one call. Kustomer first checks whether the address is still connected to an email account. If it is, nothing is deleted and `meta.live` is `true`; disconnect the account and try again. A `503` means Kustomer couldn't tell, and also deleted nothing, so retry later. Otherwise `meta.deletedCount` says how many mappings were removed.

```bash title="cURL"
curl --request DELETE "https://api.kustomerapp.com/v1/brandAddresses/address/help@oldbrand.com" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY" \
  | jq '.meta'
```

#### 4. Delete a brand you no longer use

Check what still depends on a retired brand, clear what you can, and delete it.

**Step 1.** [`GET /v1/brands/{id}/dependents`](https://developer.kustomer.com/api/core-resources/get-brand-dependents.md). Ask what would block the delete. If `deletable` is `true`, go straight to the delete. Otherwise each entry in `blockers` has a `type` and a `reason`, and any `unknown` type couldn't be checked, so try again later.

```bash title="cURL"
curl "https://api.kustomerapp.com/v1/brands/$BRAND_ID/dependents" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY" \
  | jq '.data'
```

```bash title="kusty (coming soon)"
kusty api GET /v1/brands/$BRAND_ID/dependents | jq '.data'
```

**Step 2.** [`DELETE /v1/brandAddresses/brand/{brandId}`](https://developer.kustomer.com/api/core-resources/delete-all-mappings-for-a-brand.md). A `brand_address` blocker means email addresses are still mapped to the brand. Remove them in one call. Knowledge bases, chat assistants and assistant rules that name the brand have to be removed or changed in Kustomer first.

```bash title="cURL"
curl --request DELETE "https://api.kustomerapp.com/v1/brandAddresses/brand/$BRAND_ID" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY"
```

```bash title="kusty (coming soon)"
kusty api DELETE /v1/brandAddresses/brand/$BRAND_ID --confirm --yes
```

**Step 3.** [`DELETE /v1/brands/{id}`](https://developer.kustomer.com/api/core-resources/delete-brand.md). Delete the brand. A `204` means it's done; there's no undo. A `409` means it wasn't deleted; read `errors[0].detail` to see why. `Cannot delete the default brand` has no `meta`: the default brand can never be deleted. For the other two cases, `errors[0].meta` has the same `blockers` and `unknown` lists as the dependents check. Clear the blockers, or retry later if only `unknown` has entries. PubNub keysets, AI customization profiles and Shopify storefront chat tied to the brand are cleaned up in the background afterward.

```bash title="cURL"
curl --request DELETE "https://api.kustomerapp.com/v1/brands/$BRAND_ID" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY" \
  --write-out '%{http_code}\n'
```

```bash title="kusty (coming soon)"
kusty api DELETE /v1/brands/$BRAND_ID --confirm --yes
```

> The brand stays readable with `includeDeleted=true` on [`GET /v1/brands/{id}`](https://developer.kustomer.com/api/core-resources/get-brand-by-id), so you can still show its name on old conversations.

### Example object

A real record from [`POST /v1/brands`](https://developer.kustomer.com/api/core-resources/create-brand.md):

```json
{
  "type": "brand",
  "id": "5e0f779ed95b430019b57715",
  "attributes": {
    "name": "Kustom Socks",
    "iconUrl": "https://s29093.pcdn.co/wp-content/uploads/2019/12/Kustomer_Logo-2.svg",
    "default": false,
    "createdAt": "2020-01-03T17:19:26.498Z",
    "updatedAt": "2020-01-03T17:19:26.498Z",
    "modifiedAt": "2020-01-03T17:19:26.498Z"
  },
  "relationships": {
    "org": {
      "links": {
        "self": "/v1/orgs/5d5dae1ccd1e87001a6a7ea4"
      },
      "data": {
        "type": "org",
        "id": "5d5dae1ccd1e87001a6a7ea4"
      }
    },
    "createdBy": {
      "links": {
        "self": "/v1/users/5e0e15a9b2d734001913256c"
      },
      "data": {
        "type": "user",
        "id": "5e0e15a9b2d734001913256c"
      }
    },
    "modifiedBy": {
      "links": {
        "self": "/v1/users/5e0e15a9b2d734001913256c"
      },
      "data": {
        "type": "user",
        "id": "5e0e15a9b2d734001913256c"
      }
    }
  },
  "links": {
    "self": "/v1/brands/5e0f779ed95b430019b57715"
  }
}
```

Fields:

- `attributes.name` (string): The brand's name. `PATCH` requires it together with `iconUrl`, so send the current value of whichever one you aren't changing.
- `attributes.iconUrl` (string): A URL for the brand's icon image. Like `name`, it's required on both `POST` and `PATCH`.
- `attributes.default` (boolean): Whether this is the org's default brand, which chat uses when it starts without a `brandId`. The first brand gets it when the org is created; brands you create are always `false`, and the API can't move the default.

### Relationships

- Referenced by **Knowledge bases** via `relationships.brand`: Each knowledge base belongs to exactly one brand, and a brand can have only one knowledge base. The default knowledge base uses the org's default brand.

### Permissions

Fewest roles for a read-only integration: `org.permission.brand.read`, `org.permission.apps.read`. For every endpoint: `org.permission.brand.read`, `org.permission.apps.delete`, `org.permission.apps.create`, `org.permission.apps.read`, `org.permission.apps.update`, `org.permission.brand.create`, `org.permission.brand.delete`, `org.permission.brand.update`.

## Path parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Brand ID. |

## Responses

### 200

OK

- `data` (object, required)
  - `deletable` (boolean, required): `true` only when `blockers` and `unknown` are both empty.
  - `blockers` (array<object>, required): What currently blocks the delete, one entry per type of dependent.
    - `type` (string): Kind of dependent. One of: `brand`, `knowledge_base`, `brand_address`, `chat_settings`, `assistant_settings`, `assistant_rule`, `assistant_automation`.
    - `reason` (string): Stable code describing why this blocks. New codes can be added.
    - `id` (string, nullable): ID of the dependent when it is a single one, otherwise `null`. For assistant blockers it is the assistant's ID (the automation's ID for `assistant_automation`).
    - `name` (string, nullable): Display name of the dependent when known and single, otherwise `null`.
    - `count` (integer): How many dependents of this type.
    - `channels` (array<string>): Only on `assistant_settings`. Channels with a default assistant assigned. Known values are `sms`, `whatsapp`, `sendbird-chat` and `voice`; accept other values too.
    - `assistants` (array<object>): Only on assistant blockers. The assistants in use that make this block.
  - `unknown` (array<string>, required): Types of checks that could not run. Uses the same values as `blockers[].type`, never `brand`.

```json
{
  "data": {
    "deletable": false,
    "blockers": [
      {
        "type": "knowledge_base",
        "id": "5f1c0a7e9d2b4c0012ab34cd",
        "name": "Help center",
        "reason": "knowledge_base",
        "count": 1
      },
      {
        "type": "brand_address",
        "id": null,
        "name": null,
        "reason": "brand_address",
        "count": 3
      },
      {
        "type": "assistant_settings",
        "id": "5f1f3b2a8c1d4e0013cd56ef",
        "name": "Voice agent",
        "reason": "assistant_default_assigned",
        "count": 1,
        "channels": [
          "sendbird-chat",
          "sms"
        ],
        "assistants": [
          {
            "id": "5f1f3b2a8c1d4e0013cd56ef",
            "name": "Voice agent"
          }
        ]
      }
    ],
    "unknown": [
      "chat_settings"
    ]
  }
}
```

### 400

Bad Request

### 401

Unauthorized

### 403

Forbidden

### 404

Not found. The brand does not exist in your organization or is already deleted.

## Example request

```bash
curl --request GET \
  --url 'https://api.kustomerapp.com/v1/brands/60254e3ec413ae00571e3c9c/dependents' \
  --header "Authorization: Bearer $KUSTOMER_API_KEY"
```
