# Add a competitor brand to the watchlist

`POST /v1/email/competitive/watchlist/brands`

Adds a brand to the workspace's watchlist so its figures appear next to your
own. Pass a `brand_id` from a brand search.

Adding a brand records the one domain the panel sees the most of its mail
from, and every figure reported for the brand describes that domain. A brand
that mails from several domains therefore reports less than its full volume.
A brand the panel has never seen send cannot be measured at all and is
refused.

How many brands can be watched is capped per organization, counted across
every workspace it owns, so the same competitor watched from two workspaces
uses two of the allowance.

API-key, OAuth, and service-account calls require Insights preview access for your organization.

## Code samples

### TypeScript

```ts
// Requires Insights preview access for the organization.
const matches = await bird.email.competitive.brands.search({ q: "Everlane" });
const match = matches.data.find((brand) => brand.name === "Everlane");
if (!match) throw new Error("No exact Everlane match");
const entry = await bird.email.competitive.watchlist.brands.create({ brand_id: match.brand_id });
console.log(entry.id);
```

### Python

```py
# Requires Insights preview access for the organization.
matches = client.email.competitive.brands.search(q="Everlane")
match = next((brand for brand in matches.data if brand.name == "Everlane"), None)
if match is None:
    raise ValueError("No exact Everlane match")
entry = client.email.competitive.watchlist.brands.create(brand_id=match.brand_id)
print(entry.id)
```

### Go

```go
// Requires Insights preview access for the organization.
client, err := bird.NewClient(option.WithAPIKey(os.Getenv("BIRD_API_KEY")))
if err != nil {
	log.Fatal(err)
}
ctx := context.Background()
matches, err := client.Email.Competitive.Brands.Search(ctx, bird.EmailCompetitiveBrandsSearchParams{Q: "Everlane"})
if err != nil {
	log.Fatal(err)
}
brandID := ""
if matches.Data != nil {
	for _, match := range *matches.Data {
		if match.Name != nil && *match.Name == "Everlane" && match.BrandId != nil {
			brandID = string(*match.BrandId)
			break
		}
	}
}
if brandID == "" {
	log.Fatal("No exact Everlane match")
}
report, err := client.Email.Competitive.Watchlist.Brands.Create(ctx, bird.EmailCompetitiveWatchlistBrandsCreateParams{BrandID: brandID})
if err != nil {
	log.Fatal(err)
}
encoded, err := json.MarshalIndent(report, "", "  ")
if err != nil {
	log.Fatal(err)
}
fmt.Println(string(encoded))
```

### PHP

```php
// Requires Insights preview access for the organization.
$matches = $bird->email->competitive->brands->search(['q' => 'Everlane']);
$brandId = null;
foreach ($matches->getData() ?? [] as $match) {
    if ($match->getName() === 'Everlane') {
        $brandId = $match->getBrandId();
        break;
    }
}
if ($brandId === null) {
    throw new \RuntimeException('No exact Everlane match');
}
$params = (new \MessageBird\Wire\Model\EmailCompetitiveWatchlistBrandCreate())->setBrandId($brandId);
$entry = $bird->email->competitive->watchlist->brands->create($params);
echo $entry->getId();
```

### CLI

```sh
bird email competitive watchlist brands create 81531
```

### cURL

```sh
curl -X POST "https://us1.platform.bird.com/v1/email/competitive/watchlist/brands" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "brand_id": "81531"
  }'
```

## Example response `201`

```json
{
  "created_at": "2026-05-20T09:14:52Z",
  "updated_at": "2026-05-25T16:42:01Z",
  "id": "cwb_01krdgeqcxet5s7t44vh8rt9mg",
  "brand_id": "81531",
  "name": "Everlane",
  "industry": "DTC Apparel",
  "sending_domains": [
    "everlane.com"
  ]
}
```

## Request body

- `brand_id` (string, required): Identifier of the brand in the panel's catalog, used to add it to the watchlist. It is a string for the same reason a campaign id is: the values are wide enough that a client storing every number as a floating point value would round them, and a rounded identifier matches no brand at all.

## Response body

- `created_at` (string, required)
- `updated_at` (string, required)
- `id` (string, required): The watchlist entry.
- `brand_id` (string, required)
- `name` (string, required): The brand's name when it was added. It is kept as it was so the row still reads correctly if the brand is later renamed or stops being tracked.
- `industry` (nullable string, required): The brand's industry when it was added, or null when the brand is not classified.
- `sending_domains` (array of string, required): The domains this brand's figures describe. Always one domain today, chosen as the one the panel sees the most of its mail from.

## Related resources

- [Should I use a Bird SDK or call the API directly?](/explained/platform/should-i-use-an-sdk-or-call-the-api-directly) (answer)
- [Build your first integration](/learn/paths/integration) (course)
- [Send your first email](/docs/get-started/send-your-first-email) (docs)

[Get an implementation brief](/learn/workspace?topic=api-basics)
