curl --request GET \
--url https://brew.new/api/v1/domains/{domainId}/health \
--header 'Authorization: Bearer <token>'import requests
url = "https://brew.new/api/v1/domains/{domainId}/health"
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/domains/{domainId}/health', 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/domains/{domainId}/health",
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/domains/{domainId}/health"
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/domains/{domainId}/health")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://brew.new/api/v1/domains/{domainId}/health")
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{
"domainId": "kx7bkh53hasmfeh5kd7sqgykt187g8ww",
"name": "send.example.com",
"status": "verified",
"sendable": true,
"verdict": "at_risk",
"readiness": "ready_with_warnings",
"score": {
"placementMeasured": true,
"value": 72,
"grade": "fair",
"confidence": "medium",
"components": {
"placement": {
"score": 68,
"weight": 0.35,
"basis": "seed_test"
},
"authentication": {
"score": 100,
"weight": 0.2,
"basis": "dns"
},
"reputation": {
"score": 74,
"weight": 0.2,
"basis": "org_history"
},
"content": {
"score": 62,
"weight": 0.15,
"basis": "recent_sends"
},
"posture": {
"score": 55,
"weight": 0.1,
"basis": "warmup_stage"
}
},
"trend": {
"direction": "up",
"previousScore": 64,
"previousComputedAt": "2026-06-21T09:00:00.000Z"
}
},
"authentication": {
"spf": "verified",
"dkim": "verified",
"dmarc": "missing"
},
"tracking": {
"linksStatus": "live",
"openTracking": true,
"clickTracking": true
},
"warmup": [
{
"sendId": "W7nT1vPb9Ycr4Kq8ZxL2m",
"currentTranche": 3,
"sentSoFar": 175,
"rampEndsAt": "2026-07-15T00:00:00.000Z"
}
],
"dailyVolume": [],
"domainActivity": {
"sampled": true,
"sampleSendCount": 12,
"sentCount": 2400,
"bouncedCount": 31,
"complainedCount": 1,
"bounceRate": 0.0129,
"complaintRate": 0.0004
},
"orgReputation": {
"scope": "org",
"totalSent": 18250,
"bounceRate": 0.011,
"complaintRate": 0.0003
},
"recentPlacementTests": [
{
"testId": "ibp_2f1c9d8a",
"emailId": "V1StGXR8_Z5jdHi6B-myT",
"status": "completed",
"overall": {
"total": 41,
"inbox": 33,
"spam": 8,
"missing": 0,
"pending": 0
},
"authentication": {
"spf": "pass",
"dkim": "pass",
"dmarc": "pass"
},
"spamFilterFlagged": false,
"createdAt": "2026-07-13T17:00:00.000Z"
}
],
"signals": [
{
"id": "dmarc_missing",
"severity": "warning",
"summary": "No DMARC record is configured for this domain.",
"suggestion": "Add a TXT record: _dmarc TXT \"v=DMARC1; p=reject; rua=mailto:dmarc@send.example.com\" — Gmail/Yahoo bulk-sender rules require DMARC, and it blocks spoofing."
}
],
"checkedAt": "2026-07-13T18:00:00.000Z"
}Get domain health
The domain’s deliverability health in one FREE read: a verdict (healthy / at_risk / critical) with actionable signals, DNS/auth state incl. DMARC, active percentage-based gradual sends, sampled bounce/complaint activity from campaign and automation sends, workspace reputation, and inbox-placement history. No bounce or complaint threshold is attached to a gradual-send configuration. include=scoreHistory adds scoreHistory: up to 50 saved score snapshots, newest first (score, grade, confidence, the event that saved it, and each pillar’s score and weight); only snapshots saved under this brand count, searched among the domain’s newest 500, so a domain that moved between brands can show fewer. include=scoreRuns adds scoreRuns: the last 5 automated domain score runs (the 5-variant seed check), each with its status in the shared run vocabulary, the score it ended on, the credits it cost and every variant’s placement test.
curl --request GET \
--url https://brew.new/api/v1/domains/{domainId}/health \
--header 'Authorization: Bearer <token>'import requests
url = "https://brew.new/api/v1/domains/{domainId}/health"
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/domains/{domainId}/health', 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/domains/{domainId}/health",
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/domains/{domainId}/health"
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/domains/{domainId}/health")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://brew.new/api/v1/domains/{domainId}/health")
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{
"domainId": "kx7bkh53hasmfeh5kd7sqgykt187g8ww",
"name": "send.example.com",
"status": "verified",
"sendable": true,
"verdict": "at_risk",
"readiness": "ready_with_warnings",
"score": {
"placementMeasured": true,
"value": 72,
"grade": "fair",
"confidence": "medium",
"components": {
"placement": {
"score": 68,
"weight": 0.35,
"basis": "seed_test"
},
"authentication": {
"score": 100,
"weight": 0.2,
"basis": "dns"
},
"reputation": {
"score": 74,
"weight": 0.2,
"basis": "org_history"
},
"content": {
"score": 62,
"weight": 0.15,
"basis": "recent_sends"
},
"posture": {
"score": 55,
"weight": 0.1,
"basis": "warmup_stage"
}
},
"trend": {
"direction": "up",
"previousScore": 64,
"previousComputedAt": "2026-06-21T09:00:00.000Z"
}
},
"authentication": {
"spf": "verified",
"dkim": "verified",
"dmarc": "missing"
},
"tracking": {
"linksStatus": "live",
"openTracking": true,
"clickTracking": true
},
"warmup": [
{
"sendId": "W7nT1vPb9Ycr4Kq8ZxL2m",
"currentTranche": 3,
"sentSoFar": 175,
"rampEndsAt": "2026-07-15T00:00:00.000Z"
}
],
"dailyVolume": [],
"domainActivity": {
"sampled": true,
"sampleSendCount": 12,
"sentCount": 2400,
"bouncedCount": 31,
"complainedCount": 1,
"bounceRate": 0.0129,
"complaintRate": 0.0004
},
"orgReputation": {
"scope": "org",
"totalSent": 18250,
"bounceRate": 0.011,
"complaintRate": 0.0003
},
"recentPlacementTests": [
{
"testId": "ibp_2f1c9d8a",
"emailId": "V1StGXR8_Z5jdHi6B-myT",
"status": "completed",
"overall": {
"total": 41,
"inbox": 33,
"spam": 8,
"missing": 0,
"pending": 0
},
"authentication": {
"spf": "pass",
"dkim": "pass",
"dmarc": "pass"
},
"spamFilterFlagged": false,
"createdAt": "2026-07-13T17:00:00.000Z"
}
],
"signals": [
{
"id": "dmarc_missing",
"severity": "warning",
"summary": "No DMARC record is configured for this domain.",
"suggestion": "Add a TXT record: _dmarc TXT \"v=DMARC1; p=reject; rua=mailto:dmarc@send.example.com\" — Gmail/Yahoo bulk-sender rules require DMARC, and it blocks spoofing."
}
],
"checkedAt": "2026-07-13T18:00:00.000Z"
}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 - 64Path Parameters
Domain id (opaque Convex document id) returned by POST /v1/domains and listed by GET /v1/domains.
1 - 64"kx7bkh53hasmfeh5kd7sqgykt187g8ww"
Query Parameters
Expansions: scoreHistory attaches up to 50 saved score snapshots, newest first; scoreRuns the last 5 automated domain score runs.
Response
The aggregate health report.
1 - 641 - 253not_started, pending, verified, failed, temporary_failure, partially_verified, partially_failed healthy, at_risk, critical ready, ready_with_warnings, not_ready, checking, unknown Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Deprecated — always empty. Gradual sends no longer share a per-domain daily budget.
Show child attributes
Show child attributes
Campaign and automation activity, excluding placement seeds. A bounded sample, not a time-window total. Null when no sampled recipients were sent.
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
With include=scoreHistory: up to 50 saved score snapshots, newest first. Snapshots are saved when a placement test completes, the domain is verified, or a score run finishes. Only snapshots saved under this brand count, searched among the domain's newest 500, so a domain that moved between brands can show fewer.
50Show child attributes
Show child attributes
With include=scoreRuns: the last 5 automated domain score runs (the 5-variant seed check), newest first.
5Show child attributes
Show child attributes
Was this page helpful?