Skip to main content
Brew Insights watches the brand’s email and records what it finds: deliverability problems, emails that did better or worse than usual, timing, and audience and automation opportunities. In the app, the Brew Insights cards on Home open the Insights page. Over the API, GET /v1/insights lists the findings as that page ranks them, and GET /v1/insights/{insightId} reads one in full. Both reads are free, need the emails scope, and count against the analytics.read rate limit. An organization key names the brand with X-Brand-Id, as on every brand-scoped route.

List the Findings

It answers 200 with { data, pagination, freshness }, most severe first and then by score:
description is the detector’s own headline. Quote it rather than restating its numbers. kind says what sort of finding it is: answer reports what happened, insight is a change that passed its statistical test, and strategy is a recommended next step. action, when present, either links to a page in Brew (navigate) or carries the request the Insights page would send to Brew’s assistant (assistant, with intent and prompt).

When the Findings Change Mid-Walk

The list is ranked again on every request, so it can change between pages: the engine runs, or someone snoozes or dismisses a finding. The cursor remembers which findings it has already returned.
  • A change below the cursor is served. A finding added further down the list, or one that leaves it before you reach it, is simply on (or off) its page when that page comes.
  • A change above the cursor refuses the next page. If a finding is added above the cursor, one you already have leaves the list, or a finding is re-ranked across the cursor, the next page would skip or repeat findings. It answers 400 INVALID_REQUEST with param: "cursor": “The findings changed since this cursor was issued, so its next page would skip or repeat some.” Read the list again from the first page, without cursor, with the same state and severity. Dropping them starts a different list.
So a walk that reaches its last page has returned every finding exactly once, as the list stands at that last page. A cursor also carries the state and severity that returned it. Sending it with a different state or severity is 400 INVALID_REQUEST with param: "cursor". Pass the filters that returned it, or start over from the first page without cursor. In the SDK, both refusals throw BrewApiError with code INVALID_REQUEST and param cursor. brew-cli insights list --all starts over from the first page once when the findings change during its walk.

Check Freshness Before You Report

Every page carries freshness, whatever you filter on:
  • dataAsOf is how current the data behind the findings is. It is null before the first successful run.
  • lastSuccessfulRunAt is when the engine last finished a run.
  • latestAttempt is the newest run and its status: succeeded, running, failed, or unknown. A failed attempt means the findings may be stale, so say so when you report them.

Add the Intelligence Layer

include adds what the Insights page shows beside the findings. Each expansion is a top-level key on the page. pulse, report, and memo are null until they exist, and suggestions is an empty array when there are none. The expansions describe the brand, not the page, so they are the same on every page. Ask for them on the first page only.

Read One Finding

Pass the insightId a list row carries.
The answer is the bare finding: the list row’s fields plus these.

Errors

From an Agent

Over MCP, list_insights and get_insight read the same findings, and include is an array (include: ["pulse", "report"]). list_insights reads 10 findings per page. To fit one tool result, it shortens long text on each finding (a shortened field ends in ”…”) and cuts the report, suggestions, and memo where its budget ends. A truncated array names each cut section as { section, shown, total }. For report and suggestions, shown and total count items: the report’s insights, or the suggestions. For memo they count characters of its markdown. The HTTP read has no such limit and always answers whole. A stale cursor or one from another filter comes back as a tool error naming cursor, the same refusal the HTTP read gives. From the shell, brew-cli insights list takes --state, --severity, and --include, and --all returns every finding with the expansions from the first page.

See Also

Need Help?

Our team is ready to support you at every step of your journey with Brew. Choose the option that works best for you:

Search Documentation

Type in the “Ask any question” search bar at the top left to instantly find relevant documentation pages.

ChatGPT/Claude Integration

Click “Open in ChatGPT” at the top right of any page to explore it further with ChatGPT or Claude.