POST /v1/sends returns a sendId for lifecycle status and aggregate stats.
Test sends return a completed status and recipient without a send row. Sends read at their own root: the
list is /v1/sends, and one send is a path read.
GET /v1/sends: list every campaign send for the brand, withstats.GET /v1/sends/{sendId}: one send’s lifecycle status + stats, as a bare row.GET /v1/sends/{sendId}?include=events: the same row with its per-recipient event feed inlined.GET /v1/sends?emailId=…: every send for one design.
sends scope (which emails implies), on the
sends.read rate-limit policy. POST /v1/sends is polymorphic by test
and uses sends.write.
GET /v1/analytics/sends and GET /v1/analytics/campaigns are gone.
So is the old habit of listing with ?sendId= and taking data[0]: that
query key now returns 400 INVALID_REQUEST. See
Migrating to the cleaned-up v1 surface.List Recent Sends
{ data, pagination }. See
Pagination for the cursor loop, or use the
SDK auto-pager:
scheduled, queued,
running, paused, completed, partially_completed, failed,
canceled. The older sent / sending / partially_sent spellings are
rejected as 400 INVALID_REQUEST.
Poll a Single Send
Read one send by id to watch it move fromqueued to running to
completed and to read its rolled-up stats. The response is the send row
itself, with no data wrapper. An unknown or cross-brand id returns
404 SEND_NOT_FOUND.
Read the Per-Recipient Feed
Once a send is in flight, drill into its individual delivery events:sent / delivered / opened / clicked / bounced / complained
/ unsubscribed. Add ?include=events to the single-send read to inline
a bounded first page of the feed on the same row. For the full, filterable
history, use GET /v1/analytics/events with the same sendId (see
Explore per-contact engagement).
Join an Automation Run to Its Deliveries
An automation send is one row per recipient, so it is never listed brand-wide. Pass a join filter instead andkind=automation is implied:
automationId, automationRunId, audienceRunId, or triggerInstanceId.
404 AUTOMATION_RUN_NOT_FOUND or
404 AUDIENCE_RUN_NOT_FOUND. Combining a join filter with kind=campaign
or with emailId, or asking for kind=automation without one, returns
400 INVALID_REQUEST.
Pause, Resume, or Cancel a Send
Lifecycle changes are action sub-paths, not a body verb:
A paused send carries
pauseReason. manual means someone paused it; resume
it to continue. plan_limit means the organization ran out of monthly email
sends. That send resumes on its own once the allowance has room, so resume
refuses it; cancel it if it should not go out.
Send a Test Email
The samePOST /v1/sends endpoint sends a test when you pass test: true.
A test send forces the Brew default sender unless you name a verified
org-owned domainId, requires no audience, does not write a send row,
and resolves synchronously to 200 { status: 'completed', recipient }.
test. It
returns 202 { status: 'queued' | 'scheduled' | 'pending_approval', sendId, scheduledAt? }.
pending_approval waits for an organization administrator to approve the send.
There is no runId: sendId is the only handle you need. Name the sender
with from: { email, name? } and put replyTo at the top level. See
Async jobs & polling.
Related
GET /v1/sendsin the Public API v1 reference (sidebar): full parameter + schema reference.- Errors:
SEND_NOT_FOUND,DOMAIN_NOT_READY,AUDIENCE_NOT_FOUND,SEND_QUOTA_EXCEEDED. - Migrating to the cleaned-up v1 surface: the full old-to-new map.
- Sends (SDK):
emails.send(passtest: truefor a QA send),sends.list,sends.get(include: 'events').
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:- Self-Service Tools
- Talk to Our Team
Search Documentation
Type in the “Ask any question” search bar at the top left to instantly find relevant documentation pages.
Ask ChatGPT or Claude
Click here to open the Copy page menu at the top of this page, then send the page to ChatGPT, Claude, or your editor.