curl --request GET \
--url https://brew.new/api/v1/emails/{emailId} \
--header 'Authorization: Bearer <token>'import requests
url = "https://brew.new/api/v1/emails/{emailId}"
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/emails/{emailId}', 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/emails/{emailId}",
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/emails/{emailId}"
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/emails/{emailId}")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://brew.new/api/v1/emails/{emailId}")
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{
"emailId": "V1StGXR8_Z5jdHi6B-myT",
"emailVersionId": "Yc5Kz8Sq2Wn7Lp4Tm1RvX",
"version": "latest",
"title": "Welcome Email",
"status": "ready",
"previewStatus": "available",
"subjectLine": "Welcome to Acme",
"previewText": "Your first week, planned.",
"previewImage": "https://cdn.brew.new/p/V1StGXR8_Z5jdHi6B-myT.png",
"updatedAt": "2026-04-08T12:34:56.789Z",
"group": {
"groupId": "grp_welcome",
"groupName": "Welcome"
},
"versions": [
{
"version": "latest",
"emailVersionId": "Yc5Kz8Sq2Wn7Lp4Tm1RvX"
},
{
"version": 1,
"emailVersionId": "Lw9Rn1Vc5KzSGm2Tq7Xp4"
}
]
}Get an email design
Reads one design as the bare EmailDetail row: emailId, the emailVersionId (the pin for POST /v1/sends and sendEmail nodes), title, status, previewStatus, subjectLine, previewText, previewImage, updatedAt, group and createdBy / createdByUserId (the design’s creator, shared by every version), plus errorMessage when a generation failed.
Use when inspecting a design before sending it, pinning a version, polling a generation you started, or pulling rendered HTML or version history.
Input emailId in the path. By default the row is the current head; emailVersionId reads a saved version and runId (returned by a create or edit) reads the version that run produced; pass one or neither, never both. include=html adds the selected version’s rendered HTML once it is ready, include=versions the lean { version, emailVersionId } history, include=text the visible body text a reader sees (merge tags kept; textTruncated past 20,000 characters), and include=links each link destination once with its first visible text and count (linksTruncated past 200); comma-separate any of them.
Returns 200 with the row; the include fields are present only when requested. A run that never saved a version reads as failed with the reason, and the design keeps its last saved version.
Errors 404 EMAIL_NOT_FOUND for an unknown or cross-brand id; 404 EMAIL_VERSION_NOT_FOUND for a version or run this design does not have; 409 EMAIL_RUN_AMBIGUOUS when a legacy run matches more than one version (read it by emailVersionId); 503 SERVICE_UNAVAILABLE when storage is briefly unreachable (retry the same read); 400 INVALID_REQUEST for an unknown include token or both selectors.
See also listEmails, editEmail, createSend, restoreEmailVersion.
curl --request GET \
--url https://brew.new/api/v1/emails/{emailId} \
--header 'Authorization: Bearer <token>'import requests
url = "https://brew.new/api/v1/emails/{emailId}"
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/emails/{emailId}', 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/emails/{emailId}",
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/emails/{emailId}"
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/emails/{emailId}")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://brew.new/api/v1/emails/{emailId}")
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{
"emailId": "V1StGXR8_Z5jdHi6B-myT",
"emailVersionId": "Yc5Kz8Sq2Wn7Lp4Tm1RvX",
"version": "latest",
"title": "Welcome Email",
"status": "ready",
"previewStatus": "available",
"subjectLine": "Welcome to Acme",
"previewText": "Your first week, planned.",
"previewImage": "https://cdn.brew.new/p/V1StGXR8_Z5jdHi6B-myT.png",
"updatedAt": "2026-04-08T12:34:56.789Z",
"group": {
"groupId": "grp_welcome",
"groupName": "Welcome"
},
"versions": [
{
"version": "latest",
"emailVersionId": "Yc5Kz8Sq2Wn7Lp4Tm1RvX"
},
{
"version": 1,
"emailVersionId": "Lw9Rn1Vc5KzSGm2Tq7Xp4"
}
]
}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
Design id returned by POST /v1/emails and listed by GET /v1/emails.
1 - 64"2SmZOWV3ZQ7W5x6g3m4pA"
Query Parameters
Comma-separated expansions: html (rendered HTML of the selected version, once it is ready), versions (lean { version, emailVersionId } history), text (the visible body text a reader sees), links (each link destination once, with its visible text and count).
Read this saved version instead of the current head. Mutually exclusive with runId.
1 - 64Read the version one generation run produced — the runId a create or edit returned. Mutually exclusive with emailVersionId.
1 - 128Response
The design row.
11generating, ready, failed Last stable design update. While status is generating, collection reads hold this at createdAt so body chunks do not reorder or invalidate the whole list; the completion transition publishes the final source timestamp.
Show child attributes
Show child attributes
available when previewImage is set; unavailable when a ready design has no saved screenshot; not_ready while generating or after a failure.
available, unavailable, not_ready 1The design's default inbox subject, persisted on the latest version. Distinct from title (canvas name). Detail-only; absent on rows where it has never been set (via the write surfaces' subjectLine field, or in-app). POST /v1/sends still requires an explicit subject.
The design's inbox preview line, read directly from the latest version's JSX (its single source of truth) — what a send delivers when no explicit previewText override is passed to POST /v1/sends. Detail-only; absent when the design has no .
Show child attributes
Show child attributes
Creator as Brew shows it: a name or "Former member", "API" or "MCP", or both joined ("Name · MCP"); absent when the creator cannot be named.
Creator user id; absent for an organization API key.
The version that was read: its number, or latest for the current head.
x >= 0Echoes the runId query parameter when one was passed.
MCP only: a signed, expiring download of the selected version’s HTML, in place of an html too large to inline.
Show child attributes
Show child attributes
include=text: visible body text, merge tags kept (max 20,000 chars).
include=links: each destination once (href, first visible text, count); max 200.
Show child attributes
Show child attributes
Why the generation failed. Present when status is failed.
A stable failure category, when one was recorded.
Was this page helpful?