curl --request GET \
--url https://brew.new/api/v1/analytics/overview \
--header 'Authorization: Bearer <token>'import requests
url = "https://brew.new/api/v1/analytics/overview"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://brew.new/api/v1/analytics/overview', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://brew.new/api/v1/analytics/overview",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://brew.new/api/v1/analytics/overview"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://brew.new/api/v1/analytics/overview")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://brew.new/api/v1/analytics/overview")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"totals": {
"sent": 5000,
"delivered": 4920,
"opened": 2110,
"clicked": 540,
"bounced": 80,
"complained": 3,
"unsubscribed": 12,
"failed": 0,
"suppressed": 14,
"deliveryDelayed": 2
},
"rates": {
"deliveryRate": 0.984,
"openRate": 0.4289,
"clickRate": 0.1098,
"bounceRate": 0.016,
"complaintRate": 0.0006,
"unsubscribeRate": 0.0024
},
"buckets": [
{
"at": "2026-04-08T00:00:00.000Z",
"sent": 5000,
"delivered": 4920,
"deliveryDelayed": 2,
"opened": 2110,
"clicked": 540,
"bounced": 80,
"complained": 3,
"failed": 0,
"suppressed": 14,
"unsubscribed": 12
}
],
"granularity": "1d",
"timeZone": "America/New_York",
"range": {
"from": "2026-04-01T12:34:56.789Z",
"to": "2026-04-08T12:34:56.789Z"
},
"truncated": false
}Brand overview (totals, rates, timeseries)
Windowed brand overview: the exact read behind the app’s Analytics metric cards and chart (same per-recipient dedup and machine open and click exclusion), so API, MCP and page numbers always agree. Defaults to the last 7 days.
Use when you need totals, rates and a time series for the brand or for one automation, design, audience, source, domain or recipient set. For individual rows use getEventsAnalytics.
Input Filters compose freely: source (csv of send sources), automationId, emailId, audienceId (csv, max 20), triggerEventId (csv, max 10, resolved to the automations they wire), domain (sending domain) and recipient (csv of recipient rules, same grammar as getEventsAnalytics). A single filter is answered from pre-aggregated rollups; any combination, and anything with domain or recipient, aggregates raw events instead: exact but capped, so watch truncated on wide windows.
Returns 200 { totals, rates, buckets, granularity, timeZone, range, truncated }; truncated: true means the window exceeded the scan budget, so narrow the range. Requires the emails scope.
Errors 400 INVALID_REQUEST for an inverted window or too many csv values.
See also getEventsAnalytics, getAutomationAnalytics, listSends (campaign rows carry their own stats).
curl --request GET \
--url https://brew.new/api/v1/analytics/overview \
--header 'Authorization: Bearer <token>'import requests
url = "https://brew.new/api/v1/analytics/overview"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://brew.new/api/v1/analytics/overview', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://brew.new/api/v1/analytics/overview",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://brew.new/api/v1/analytics/overview"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://brew.new/api/v1/analytics/overview")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://brew.new/api/v1/analytics/overview")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"totals": {
"sent": 5000,
"delivered": 4920,
"opened": 2110,
"clicked": 540,
"bounced": 80,
"complained": 3,
"unsubscribed": 12,
"failed": 0,
"suppressed": 14,
"deliveryDelayed": 2
},
"rates": {
"deliveryRate": 0.984,
"openRate": 0.4289,
"clickRate": 0.1098,
"bounceRate": 0.016,
"complaintRate": 0.0006,
"unsubscribeRate": 0.0024
},
"buckets": [
{
"at": "2026-04-08T00:00:00.000Z",
"sent": 5000,
"delivered": 4920,
"deliveryDelayed": 2,
"opened": 2110,
"clicked": 540,
"bounced": 80,
"complained": 3,
"failed": 0,
"suppressed": 14,
"unsubscribed": 12
}
],
"granularity": "1d",
"timeZone": "America/New_York",
"range": {
"from": "2026-04-01T12:34:56.789Z",
"to": "2026-04-08T12:34:56.789Z"
},
"truncated": false
}Authorizations
Send your Brew API key as Authorization: Bearer brew_xxx.
Headers
The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise 400 BRAND_ID_REQUIRED — there is no default brand); list ids with GET /v1/brands. Brand-scoped credentials may omit it, and sending a different brand returns 403 BRAND_SCOPE_MISMATCH. A brand outside your organization returns 404 BRAND_NOT_FOUND.
1 - 64Query Parameters
CSV of send sources to include (e.g. audience,api; valid values: audience, api, automation_manual, automation_integration, automation_custom). Composes with every other filter.
1 - 256CSV of automation ids (max 20) — a single id is still valid. Composes with every other filter; one id reads a pre-aggregated rollup partition, several take the raw-event path.
1 - 2048Scope to one email design. Composes with every other filter — a design used by several automations can be narrowed with automationId.
1 - 64CSV of audience ids (max 20). Composes with every other filter.
1 - 2048CSV of integration trigger-event ids (max 10), resolved to their wired automations. Composes with every other filter.
1 - 2048Sending domain (fromEmail match). Has no rollup dimension, so requests carrying it are answered from raw events — check truncated on wide windows.
1 - 255CSV of recipient rules (max 10) matching who RECEIVED the email — the SAME grammar and the same parameter name as GET /v1/analytics/events, so one filter string moves between the two and the totals here describe exactly the rows that feed lists. A full address matches exactly, @domain matches the domain, any other text matches as a substring; prefix ! to exclude (e.g. @clay.com,!ceo@clay.com). Includes OR together; excludes always apply. Like domain this has no rollup dimension (stored rows aggregate ACROSS recipients), so requests carrying it are answered from raw events — check truncated on wide windows.
1 - 2048Response
Brand-wide totals, rates, and a zero-filled timeseries for the window.
Was this page helpful?