Get one campaign a watched brand sent
GET
/v1/email/competitive/watchlist/brands/{watchlist_brand_id}/campaigns/{campaign_id}
// Requires Insights preview access for the organization.
const watchlist = await bird.email.competitive.watchlist.get({ range: 30 });
const entry = watchlist.data.find((row) => row.name === "Everlane" && row.watchlist_brand_id);
if (!entry?.watchlist_brand_id) throw new Error("Add Everlane to the watchlist first");
const watchlistBrandId = entry.watchlist_brand_id;
const page = await bird.email.competitive.watchlist.brands.campaigns.list(watchlistBrandId, { range: 30, limit: 1 });
const campaign = page.data[0];
if (!campaign) throw new Error("No captured campaigns");
const report = await bird.email.competitive.watchlist.brands.campaigns.get(watchlistBrandId, campaign.id);
console.log(report);# Requires Insights preview access for the organization.
watchlist = client.email.competitive.watchlist.get(range=30)
entry = next((row for row in watchlist.data if row.name == "Everlane" and row.watchlist_brand_id), None)
if entry is None or entry.watchlist_brand_id is None:
raise ValueError("Add Everlane to the watchlist first")
watchlist_brand_id = entry.watchlist_brand_id
campaign_id = None
for campaign in client.email.competitive.watchlist.brands.campaigns.list(watchlist_brand_id, range=30, limit=1):
campaign_id = campaign.id
break
if campaign_id is None:
raise ValueError("No captured campaigns")
report = client.email.competitive.watchlist.brands.campaigns.get(watchlist_brand_id, campaign_id)
print(report.model_dump_json())// 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()
watchlist, err := client.Email.Competitive.Watchlist.Get(ctx, bird.EmailCompetitiveWatchlistGetParams{Range: 30})
if err != nil {
log.Fatal(err)
}
watchlistBrandID := ""
if watchlist.Data != nil {
for _, row := range *watchlist.Data {
if row.Name != nil && *row.Name == "Everlane" && row.WatchlistBrandId != nil {
watchlistBrandID = string(*row.WatchlistBrandId)
break
}
}
}
if watchlistBrandID == "" {
log.Fatal("Add Everlane to the watchlist first")
}
campaignID := ""
for campaign, err := range client.Email.Competitive.Watchlist.Brands.Campaigns.List(ctx, watchlistBrandID, bird.EmailCompetitiveWatchlistBrandsCampaignsListParams{Range: 30, Limit: 1}) {
if err != nil {
log.Fatal(err)
}
if campaign.Id != nil {
campaignID = *campaign.Id
break
}
}
if campaignID == "" {
log.Fatal("No captured campaigns")
}
report, err := client.Email.Competitive.Watchlist.Brands.Campaigns.Get(ctx, watchlistBrandID, campaignID)
if err != nil {
log.Fatal(err)
}
encoded, err := json.MarshalIndent(report, "", " ")
if err != nil {
log.Fatal(err)
}
fmt.Println(string(encoded))// Requires Insights preview access for the organization.
$watchlist = $bird->email->competitive->watchlist->get(['range' => 30]);
$watchlistBrandId = null;
foreach ($watchlist->getData() ?? [] as $row) {
if ($row->getName() === 'Everlane' && $row->getWatchlistBrandId() !== null) {
$watchlistBrandId = $row->getWatchlistBrandId();
break;
}
}
if ($watchlistBrandId === null) {
throw new \RuntimeException('Add Everlane to the watchlist first');
}
$page = $bird->email->competitive->watchlist->brands->campaigns->list($watchlistBrandId, ['range' => 30, 'limit' => 1])->fetch();
$campaignId = ($page->data[0] ?? null)?->getId();
if ($campaignId === null) {
throw new \RuntimeException('No captured campaigns');
}
$report = $bird->email->competitive->watchlist->brands->campaigns->get($watchlistBrandId, $campaignId);
var_dump($report);bird email competitive watchlist brands campaigns get <watchlist-brand-id> <campaign-id>curl -X GET "https://us1.platform.bird.com/v1/email/competitive/watchlist/brands/{watchlist_brand_id}/campaigns/{campaign_id}" \
-H "Authorization: Bearer $TOKEN"响应200
{
"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
}
Returns one campaign an email panel observed a watched brand sending. It carries the
same figures the brand's campaign list gives for that campaign, so a page can open one
campaign without reading the whole list first.
The campaign has to be one the brand in the path sent. An identifier that belongs to
another brand's campaign comes back as not found, whether or not the panel holds it. A
workspace can read the campaigns of the brands it watches, and no others.
The panel folds a day of low-volume sending into one synthetic entry, and the campaign
list leaves those out. They stand for a day of sending rather than for a campaign
anyone sent, so they come back as not found here as well.
API-key calls require Insights preview access for your organization.
参数
watchlist_brand_id
string
The watched brand that sent the campaign.
campaign_id
string
The campaign to return, taken from the brand's campaign list.
响应载荷
id
string
必填
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.
subject
string
必填
The subject line the panel saw on this campaign.
sent_at
string
必填
When the panel first saw this campaign arrive.
image_url
nullable string
必填
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.
reach
nullable integer
必填
Estimated recipients this campaign reached, null when the panel observed the campaign but published no estimate for it.
read_rate
nullable number
必填
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.
has_creative
boolean
必填
Whether the panel captured the rendered email for this campaign.
discount_percent
nullable number
必填
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.
inbox_rate
nullable number
必填
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.
spam_rate
nullable number
必填
Share of this campaign that was filed as spam, null on the same terms.