# Get the notable campaigns across watched brands

`GET /v1/email/competitive/watchlist/notable`

Returns the campaigns worth a second look across every brand the workspace watches,
surfaced for what they did rather than for when they were sent.

Each campaign carries the signal that surfaced it: an unusually big send for its brand,
a campaign read unusually well for its brand, or heavy spam placement at one mailbox
provider. Every signal compares a campaign against its own brand's history, never
against your other brands, so several brands can carry the same signal in one period.

Up to 100 findings are returned. Selection takes turns across brands in watchlist order
until the response is full, prioritizing spam placement, biggest sends, then read-rate
standouts within a brand. Returned findings retain watchlist, signal, domain, and source
order. Your own sending is never included.

An empty list is an ordinary answer, not a failure: a signal only fires on a campaign
that stands out for its own brand, and a watchlist of steady senders produces nothing.
Check `panel_status` to tell that apart from the panel being unreachable.

This is a separate request from the watchlist on purpose, so a slow or degraded panel
read cannot delay the watchlist itself.

API-key calls require Insights preview access for your organization.

## Code samples

### TypeScript

```ts
// Requires Insights preview access for the organization.
const report = await bird.email.competitive.watchlist.notable({ range: 30 });
console.log(report);
```

### Python

```py
# Requires Insights preview access for the organization.
report = client.email.competitive.watchlist.notable(range=30)
print(report.model_dump_json())
```

### 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()
report, err := client.Email.Competitive.Watchlist.Notable(ctx, bird.EmailCompetitiveWatchlistNotableParams{Range: 30})
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.
$report = $bird->email->competitive->watchlist->notable(['range' => 30]);
var_dump($report);
```

### CLI

```sh
bird email competitive watchlist notable
```

### cURL

```sh
curl -X GET "https://us1.platform.bird.com/v1/email/competitive/watchlist/notable" \
  -H "Authorization: Bearer $TOKEN" \
  --url-query "range=30"
```

## Example response `200`

```json
{
  "period": {
    "days": 30,
    "from": "2026-07-13T09:00:00Z",
    "to": "2026-08-12T09:00:00Z"
  },
  "panel_status": "ok",
  "data": [
    {
      "watchlist_brand_id": "cwb_01krdgeqcxet5s7t44vh8rt9mg",
      "brand_name": "Allbirds",
      "signal": "read_rate_standout",
      "claim": {
        "text": "Biggest send in 7 days"
      },
      "evidence": {
        "ratio_to_median": 29.61,
        "read_rate_observations": 66,
        "mailbox_provider_spam_rate": 0.79,
        "mailbox_provider_observations": 199
      },
      "mailbox_provider": "gmail",
      "campaign": {
        "id": "3914827265",
        "subject": "The Summer Sale: 40% off everything",
        "sent_at": "2026-08-09T14:02:00Z",
        "image_url": "https://images.example.com/creatives/c154c8c4-6356-40e6-92d2-7c6727ec36ca.jpg",
        "reach": 410000,
        "read_rate": 0.228,
        "has_creative": true,
        "discount_percent": 40,
        "inbox_rate": 0.879,
        "spam_rate": 0.121
      }
    }
  ],
  "truncated": false
}
```

## Query parameters

- `range` (integer)

  How many days back the response covers, counting from now. One of three fixed trend windows rather than an open date range, matching how a competitive-intelligence chart is read. Defaults to 30.

  Possible values: `7`, `30`, `90`

## Response body

- `period` (object, required)

  The period the campaigns were observed in, as the panel resolved it.

  Two things differ from the other competitive reads. It ends at the last instant of
  the previous whole day rather than at the moment of the request, so a campaign sent
  this morning is never among these. And the panel holds its selection for a period
  once it has made it, so two requests a minute apart return the same campaigns rather
  than differing slightly.
- `period.days` (integer, required): Length of the period in days.
- `period.from` (string, required): Start of the period, inclusive.
- `period.to` (string, required): End of the period, exclusive. Daily figures therefore run through the previous whole UTC day and never include the one in progress.
- `panel_status` (string, required)

  Whether the panel could be read for this feed, and when it could not, why.

  Possible values: `ok`, `not_in_panel`, `no_data`, `unavailable`
- `data` (array of object, required)

  Up to 100 campaigns selected across watched brands. Selection takes turns across
  brands in watchlist order until the response is full, prioritizing spam placement,
  biggest sends, then read-rate standouts within each brand. Within one signal, rows
  compare the matching spam rate, volume ratio, or read rate descending; missing values
  sort last and ties retain tracked-domain and source order. Selected rows are returned
  in watchlist order, then biggest-send, read-rate, and spam signal order, followed by
  tracked-domain and source order.

  One campaign may appear once per signal because each row carries different evidence.
  Empty when nothing qualified; check `panel_status` to distinguish that from an
  unavailable panel.
- `data.watchlist_brand_id` (string, required): The watchlist entry that sent it.
- `data.brand_name` (string, required): The brand's name.
- `data.signal` (string, required)

  Why this campaign was surfaced. The set is open and grows as new signals are added.

  Every signal describes the campaign against its own brand's history, never against the
  other brands you watch, so several brands can carry the same signal in one period and
  none of them is the top of anything.

  `biggest_send` is a send far above that brand's own median: unusual for the brand, not
  merely large. `read_rate_standout` is a campaign read unusually well for its brand.
  `landing_in_spam` is one heavily filed as spam at a single mailbox provider, named in
  `mailbox_provider`, which is worth seeing even when the brand's overall placement looks healthy.

  Possible values (may grow over time): `biggest_send`, `read_rate_standout`, `landing_in_spam`
- `data.claim` (nullable object, required): The panel's own headline for this campaign, or null where it surfaced the campaign without making one. Null is the common case and is not a fault.
- `data.claim.text` (string, required): The panel's own phrasing, which may name the window the claim was measured over ("Biggest send in 7 days") or not ("Best-read campaign"). Show it as written rather than rebuilding it from the signal, and do not parse a window out of it.
- `data.evidence` (object, required): The figures behind the signal, for ordering or filtering the list.
- `data.evidence.ratio_to_median` (nullable number, required): How many times the brand's own median volume this send was. A value of 29 means the send was twenty-nine times the brand's typical volume for the period. Null on every signal other than `biggest_send`, and on a `biggest_send` campaign the panel published no ratio for.
- `data.evidence.read_rate_observations` (nullable integer, required): How many panel observations `campaign.read_rate` was measured over. A rate over thirty observations and one over a hundred and forty are not equally worth showing, and this is what separates them. Null on every signal other than `read_rate_standout`, and on a `read_rate_standout` campaign the panel published no denominator for.
- `data.evidence.mailbox_provider_spam_rate` (nullable number, required): Share of this campaign filed as spam at the one provider named in `mailbox_provider`, as a value between 0 and 1. A different measurement from the campaign's overall `spam_rate`, and the one this signal is about. Null on every signal other than `landing_in_spam`, and on a `landing_in_spam` campaign whose provider counts the panel did not publish, so a spam entry can arrive without the rate behind it.
- `data.evidence.mailbox_provider_observations` (nullable integer, required): How many observations at that provider `mailbox_provider_spam_rate` was measured over. Null on the same terms.
- `data.mailbox_provider` (nullable string, required): The provider a `landing_in_spam` campaign was heavily filed as spam at: spam placement is measured per provider, and this campaign's problem is at one of them. Null on every other signal.
- `data.campaign` (object, required)

  The campaign itself. Two of its fields behave differently here than on the brand's
  campaign feed, because the panel sends less about a campaign it surfaced this way.

  `has_creative` reports whether a capture came back with this entry rather than whether
  the panel ever captured the email, and captures are frequently absent here by design, so
  expect `false` on campaigns the panel did image. `reach` is null on every entry, because
  the panel does not estimate an audience for the campaigns it surfaces.
- `data.campaign.id` (string, required)

  The identifier for this campaign. Use it to fetch this one campaign on its own.

  It is a string, and it needs to stay one. The values are long enough that
  JavaScript, and any other language that stores every number as a floating point
  value, will round them, and a rounded identifier matches no campaign at all.
  Compare it and pass it back as text.
- `data.campaign.subject` (string, required): The subject line the panel saw on this campaign.
- `data.campaign.sent_at` (string, required): When the panel first saw this campaign arrive.
- `data.campaign.image_url` (nullable string, required): Where the panel's capture of the rendered email can be fetched, null when it captured none. Panels image only some of what they observe, so an absent creative is an ordinary outcome rather than a failed one. The image is served from the panel's own host rather than from ours, so a page embedding it has to allow that host.
- `data.campaign.reach` (nullable integer, required): Estimated recipients this campaign reached, null when the panel observed the campaign but published no estimate for it.
- `data.campaign.read_rate` (nullable number, required): Estimated share of recipients who read this campaign, null when the panel published no rate for it. Panel read rates count dwell time, so they do not move with the automatic opens that inflate a sender's own open rate.
- `data.campaign.has_creative` (boolean, required): Whether the panel captured the rendered email for this campaign.
- `data.campaign.discount_percent` (nullable number, required): The discount the subject line leads with, null when it names none. Read from the subject text, so it finds a stated offer and not one revealed inside the email.
- `data.campaign.inbox_rate` (nullable number, required): Share of this campaign that reached an inbox, null when the panel observed it without recording where it landed. It describes this send rather than the brand's domain, so a single bad campaign is visible against a brand whose overall placement still looks healthy.
- `data.campaign.spam_rate` (nullable number, required): Share of this campaign that was filed as spam, null on the same terms.
- `truncated` (boolean, required): Whether Bird omitted eligible panel findings to keep this response to 100 rows. False does not promise that the panel observed every qualifying campaign in the period.

## 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)
