diff --git a/source/includes/rest/_workflows.md b/source/includes/rest/_workflows.md
index 70030c15eac..f2beb878d46 100644
--- a/source/includes/rest/_workflows.md
+++ b/source/includes/rest/_workflows.md
@@ -305,6 +305,7 @@ const body = await response.json();
"properties": { "automation_email_id": "957660884" },
"incomplete": false,
"actions_required": [],
+ "email": { "id": "957660884", "subject": "Welcome, {{ subscriber.first_name }}!" },
"derived": {
"type_name": "Send an email to a person",
"summary": "Send \"Welcome!\"",
@@ -435,7 +436,7 @@ branch still has an id.
action |
- id, type, action_type, provider_id, status, properties, incomplete, actions_required |
+ id, type, action_type, provider_id, status, properties, incomplete, actions_required, email (send_email only) |
type_name, summary, email_title |
@@ -497,6 +498,13 @@ Some configuration is never published. A `drip/http_post` action responds with a
credentials; only `derived.type_name` survives. Raw segmentation criteria, provider credentials,
and editor layout data are not published on any node.
+A `send_email` action whose email exists also carries an `email` object with the email's `id` and
+`subject`. `email.id` is the email's public id: pass it to
+[Fetch a workflow email](#fetch-a-workflow-email) for the preheader and full HTML and text bodies.
+Use `email.id` rather than `properties.automation_email_id`, which is published as stored and may
+hold a legacy id that endpoint does not accept. The subject is as stored, with any Liquid tags
+verbatim, and is null or empty on a draft whose subject has not been written.
+
### Derived text
Human-readable text lives in a `derived` object, separate from `properties`. Everything in
@@ -575,6 +583,199 @@ an `ETag`, and a change confined to a withheld field does not invalidate one.
None.
+## Fetch a workflow email
+
+Returns one email a workflow sends: its subject, preheader, and full HTML and text bodies, along
+with its name, builder type, and sender. It is read-only.
+
+The email is identified by its public id, the `email.id` a `send_email` action carries in
+[Fetch a workflow's details](#fetch-a-workflow-39-s-details). An email is returned only through a
+workflow with a `send_email` step that names it.
+
+> To fetch a workflow email:
+
+```shell
+curl "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/workflows/WORKFLOW_ID/emails/WORKFLOW_EMAIL_ID" \
+ -H 'User-Agent: Your App Name (www.yourapp.com)' \
+ -u YOUR_API_KEY:
+```
+
+```ruby
+require "net/http"
+require "json"
+
+uri = URI("https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/workflows/WORKFLOW_ID/emails/WORKFLOW_EMAIL_ID")
+
+request = Net::HTTP::Get.new(uri)
+request.basic_auth("YOUR_API_KEY", "")
+request["User-Agent"] = "Your App Name (www.yourapp.com)"
+
+response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
+ http.request(request)
+end
+
+puts response.body
+```
+
+```javascript
+const response = await fetch(
+ "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/workflows/WORKFLOW_ID/emails/WORKFLOW_EMAIL_ID",
+ {
+ headers: {
+ "User-Agent": "Your App Name (www.yourapp.com)",
+ "Authorization": "Basic " + Buffer.from("YOUR_API_KEY:").toString("base64")
+ }
+ }
+);
+
+const body = await response.json();
+```
+
+> The response looks like this:
+
+```json
+# The emails property is an array of one email object.
+{
+ "links": {
+ "emails.account": "https://api.getdrip.com/v2/accounts/{emails.account}",
+ "emails.workflow": "https://api.getdrip.com/v2/{emails.account}/workflows/{emails.workflow}"
+ },
+ "emails": [
+ {
+ "id": "957660884",
+ "href": "https://api.getdrip.com/v2/9999999/workflows/12345/emails/957660884",
+ "node_id": "4e5f6a7b",
+ "email_id": 4455661,
+ "name": "Welcome!",
+ "builder_type": "text",
+ "from_name": "John Doe",
+ "from_email": "john@acme.com",
+ "reply_to": "support@acme.com",
+ "subject": "Welcome, {{ subscriber.first_name }}!",
+ "preheader": "Here's how to get started",
+ "html_body": "Hi {{ subscriber.first_name }},
{% if subscriber.tags contains 'vip' %}Thanks for being a VIP.
{% endif %}",
+ "text_body": "Hi {{ subscriber.first_name }},",
+ "created_at": "2026-01-04T17:22:03Z",
+ "updated_at": "2026-07-28T14:02:11Z",
+ "links": {
+ "account": "9999999",
+ "workflow": "12345"
+ }
+ }
+ ]
+}
+```
+
+**Properties**
+
+
+
+
+ | Property |
+ Description |
+
+
+
+
+ id |
+ The email's public id. The same value as email.id on the send_email action that sends it. |
+
+
+ href |
+ The url designated for retrieving the email via the REST API. |
+
+
+ node_id |
+ The id of the send_email node in Fetch a workflow's details that sends the email. |
+
+
+ email_id |
+ The value the Metrics endpoint returns as email_id for this email, so it joins the email to its performance. Not the id this endpoint takes; use id. |
+
+
+ name |
+ The name assigned to the email. |
+
+
+ builder_type |
+ The editor the email was built with, whether text or visual (the Visual Email Builder). |
+
+
+ from_name |
+ The From name set on the email. May be null. |
+
+
+ from_email |
+ The From email address set on the email. May be null. |
+
+
+ reply_to |
+ The Reply-To address set on the email. May be null. |
+
+
+ subject |
+ The subject line. |
+
+
+ preheader |
+ The preheader text. |
+
+
+ html_body |
+ The HTML body. For a Visual Email Builder email, this is the full generated HTML; for other emails, it is the body only, without the account's email template or footer. |
+
+
+ text_body |
+ The plain text body. |
+
+
+ created_at |
+ A timestamp representing when the email record was first created. |
+
+
+ updated_at |
+ A timestamp representing when the email record was last updated. |
+
+
+ links |
+ An object containing the ids of the account and the workflow. |
+
+
+
+
+Content is returned as stored, as it is for Single-Email Campaigns: Liquid tags such as
+`{{ subscriber.first_name }}` and `{% if %}` blocks appear verbatim and are not rendered for any
+subscriber. `subject`, `preheader`, and the bodies may be null or empty when not yet written, as on
+a draft email.
+
+New fields may be added at any time. Ignore fields you do not recognize.
+
+### Not found
+
+> If no `send_email` step in the workflow names the email, responds with a `404 Not Found`:
+
+```json
+{
+ "errors": [{
+ "code": "not_found_error",
+ "message": "This workflow has no send-email step for that email id. Use the `email.id` of a send_email action from get_workflow_details: the email's public id."
+ }]
+}
+```
+
+The same 404 is returned for the id of a Single-Email Campaign, of an Email Series Campaign email,
+or of an email sent by a rule or a form, or an old id from `properties.automation_email_id`: only
+the public id in `email.id` is accepted. A workflow that does not exist or is archived responds with
+the standard `404 Not Found` described in [Errors](#errors).
+
+### HTTP Endpoint
+
+`GET /v2/:account_id/workflows/:workflow_id/emails/:workflow_email_id`
+
+### Arguments
+
+None.
+
## Activate a workflow
> To activate a workflow: