Broadcasts
Every operation in this group: what it accepts, what it returns and the errors it can answer with.
Operations
One message sent to everybody in one or more audiences, as a separate copy for each person, personalised from the contact with merge fields and carrying a one-click unsubscribe. The sending happens in the background: create the broadcast, then read it for its progress, and list its copies with GET /emails?broadcastId=.
Every copy carries the unsubscribe headers the large mailbox providers require of bulk mail, and a person who unsubscribes is skipped by every later broadcast to those audiences. The suppression list applies as it does to every send.
/broadcasts/broadcasts/broadcasts/preview/broadcasts/analytics/broadcasts/{id}/broadcasts/{id}/broadcasts/{id}/recipients/broadcasts/{id}/recipients/{emailId}/broadcasts/{id}/stats/broadcasts/{id}/cancel/broadcasts/drafts/broadcasts/test/broadcasts/{id}/send/broadcasts/{id}/duplicate/broadcasts/{id}/resend
GET/broadcasts
List broadcasts
Every broadcast in this workspace, newest first, one page at a time, each with live counts. audienceId keeps the ones that were sent to that audience, among others or alone.
The individual messages are not here. List them with GET /emails?broadcastId=.
A key limited to particular addresses or domains lists only the broadcasts sent from an address or domain it holds.
Requires the emails:read scope.
Query parameters
limitintegerRows per page, 1 to 100.
At least 1At most 100Default25cursorstringA broadcast id. Keyset, not offset: pass the previous page's
nextCursor. One that names nothing in this list is a 400invalid_cursor.audienceIdstringOnly the broadcasts that included this audience. An id that names no audience answers an empty list rather than a 404.
1 to 64 characters
Returns
A page of broadcasts, newest first.
Errors
- 400
invalid_cursorwhencursornames no broadcast in this workspace.- 422
invalid_parameteron alimitout of range.
The errors every operation can return401403404429500Error catalog
Also available in
- TypeScript
nextmail.broadcasts.list()nextmail.broadcasts.listAll()nextmail.broadcasts.iterate()- Python
broadcasts.list()broadcasts.list_all()broadcasts.iterate()- Ruby
broadcasts.listbroadcasts.list_allbroadcasts.iterate- PHP
broadcasts->listbroadcasts->listAllbroadcasts->iterate- Go
Broadcasts.ListBroadcasts.ListAllBroadcasts.Iterate- Java
broadcasts().listbroadcasts().listAllbroadcasts().iterate- C#
Broadcasts.ListAsyncBroadcasts.ListAllAsyncBroadcasts.IterateAsync- CLI
openemail broadcasts list- MCP
listBroadcasts
POST/broadcasts
Send to audiences
Sends one message to everybody in one or more audiences, as a separate copy for each person. Every copy has exactly one recipient and no cc or bcc, so nobody sees who else it went to, and every copy is an ordinary email with its own msg_ id, events, tracking and webhooks. GET /emails?broadcastId= lists them. Copies are not filed in the Sent folder: the broadcast is the record.
The call answers 202 straight away with the broadcast queued, or scheduled when scheduledAt is set, and the sending happens in the background, 50 people at a time. Read GET /broadcasts/{id} for status and counts as it goes.
WHO GETS IT. Every contact in at least one of audienceIds, counted once however many of them hold it, except a person who has unsubscribed (GET /suppressions/unsubscribes lists them), and except an address on the suppression list. A contact in one of excludeAudienceIds is left out too, even when they are in one of audienceIds. audienceIds cannot name All contacts, the built-in audience that holds everyone this workspace has ever written to, because most of those people never asked for its mail: that is a 422 audience_is_everyone, and a send to it that was scheduled before this rule fails when its time comes. A contact added to one of the audiences after this call but before the sending reaches it is included. counts.recipients is the estimate taken now, and POST /broadcasts/preview returns the same count without sending anything.
QUOTA. The whole send is checked against the plan's monthly sends before anything is written. A broadcast the allowance cannot cover is refused with 429 send_quota_exceeded and leaves nothing behind. Each copy counts as one send.
PERSONALISATION. subject, html and text take merge fields, filled in for each person: {{firstName}}, {{lastName}}, {{name}}, {{email}}, {{unsubscribeUrl}}. Each takes a fallback after a bar, such as {{firstName|there}}, used when the contact has no value for it. The values come from the contact: the first name is the first word of its name and the last name is the rest. A custom field of the contact is {{attributes.<key>}}, such as {{attributes.plan|Free}}, and reads as its fallback, or as nothing, when the contact has no such field. Every value is escaped in html, and any other {{…}} is left as written. With template, the five values above are passed as props, but only the props the template declares, except unsubscribeUrl, which every template receives.
UNSUBSCRIBE. Every copy carries List-Unsubscribe and List-Unsubscribe-Post: List-Unsubscribe=One-Click, which is what lets a mail client offer its own unsubscribe button and what the large mailbox providers require of bulk mail. A body or a template that does not place {{unsubscribeUrl}} itself gets a short footer with the link, in English, which also names the sender and shows the postal address once marketingPostalAddress is set on PATCH /settings. A template receives unsubscribeUrl whether it declares it or not, so one that places it decides where the link goes. The link opens a page with an Unsubscribe button, and following it unsubscribes the person from all of this workspace's marketing mail: every audience they are in shows unsubscribedAt on GET /audiences/{id}/contacts, they are listed on GET /suppressions/unsubscribes, and later broadcasts and automation emails skip them, even after they are added to an audience again or their contact is deleted and made again. Their contact and mail sent to them one message at a time are not affected.
LIMITS. 1 to 10 audiences and up to 8 tags, and every copy also carries the tag broadcast_id. No attachments, cc, bcc, translation or encryption. The body comes from html and or text, or from template, never both.
IDEMPOTENCY. Send an Idempotency-Key and a retry with the same key answers 200 with the broadcast the first call created, with replayed: true and Idempotency-Replayed: true, instead of sending again. The same key with a different body is a 422 idempotency_key_reuse. Without a key, sending the same body twice sends the broadcast twice.
Requires the emails:send and audiences:read scopes.
Headers
Idempotency-KeystringMakes a retry safe. Reusing one with a different body is a 422.
Up to 255 charactersPattern^[A-Za-z0-9_.:-]+$
Request body
audienceIdsstring[]Required1 to 10 audience ids. A contact in several of them gets one copy. Each id has to name an audience in this workspace, or nothing is sent.
1 to 10 itemsexcludeAudienceIdsstring[]Up to 10 audiences whose members are left out, even when they are also in one of
audienceIds, such as the customers who already bought. All contacts may be named here.Up to 10 itemssegmentIdstringA saved segment that narrows the audiences: only the contacts that match its conditions get a copy, such as the people who opened in the last 90 days. The conditions are read when the broadcast is sent or scheduled and kept with it, so editing the segment later changes nothing that is already on its way. Resending to the people who did not open leaves the segment out, because they already passed it.
1 to 64 charactersfromstring | objectRequiredThe sender, as on
POST /emails: an address the key may send as, bare or with a name.emailstringRequired- Up to 320 characters
namestring- Up to 128 characters
replyTostring | objectWhere replies go, the same for every copy.
emailstringRequired- Up to 320 characters
namestring- Up to 128 characters
subjectstringRequired unless a template supplies it. Takes merge fields:
{{firstName}},{{lastName}},{{name}},{{email}},{{unsubscribeUrl}}, and{{attributes.<key>}}for a custom field of the contact, each with an optional fallback after a bar, such as{{firstName|there}}.Up to 998 charactersDefault""htmlstringThe HTML body, with the same merge fields, their values escaped. Without
{{unsubscribeUrl}}in it, a one-line unsubscribe footer is added.Up to 1000000 characterstextstringThe plain text body, with the same merge fields. Without
{{unsubscribeUrl}}in it, an unsubscribe line is added.Up to 1000000 characterstemplateobjectA stored template instead of
htmlandtext. The merge values are passed as props, but only the ones the template declares, exceptunsubscribeUrl, which every template receives. A template that does not place it gets the same footer as a body.idstringRequired- 1 to 128 characters
versioninteger- More than 0At most 100000
propsRecord<string, any>slotsRecord<string, any>
trackingobjectOpen and link tracking for every copy. A field left out takes the
fromaddress setting, as onPOST /emails.opensbooleanclicksboolean
tagsRecord<string, string>Up to 8 tags, copied onto every copy beside
broadcast_id, which the server adds.Default{}utmobjectCampaign tags added to every http and https link in the body:
source,medium,campaign,termandcontentbecomeutm_sourceand the rest, so the visits show up in your web analytics. A link that already carries one keeps its own value, and the unsubscribe link never gets them. Values are 1 to 100 characters,campaignup to 200.sourcestring- 1 to 100 characters
mediumstring- 1 to 100 characters
campaignstring- 1 to 200 characters
termstring- 1 to 100 characters
contentstring- 1 to 100 characters
abTestobjectAn A/B test.
variantsholds 2 to 4 versions, each asubject, or a body ashtmland ortext, that replaces the broadcast's own, so{}keeps the broadcast as it is.testPercent(5 to 50, 20 unless set) of the people get a variant, split evenly between them, andmetric(opensunless set, orclicks) picks the winner oncewaitMinutes(30 to 4320, 240 unless set) have passed since the test went out. Everybody else then gets the winning variant. The rate counts the people who opened or clicked out of the copies each variant sent, a tie goes to the earlier variant, and with nothing to compare the first variant wins. A template broadcast can only vary the subject.variantsobject[]Required- 2 to 4 items
subjectstring- 1 to 998 characters
htmlstring- 1 to 1000000 characters
textstring- 1 to 1000000 characters
testPercentinteger- At least 5At most 50Default
20 metricstring- One of
"opens""clicks"Default"opens" waitMinutesinteger- At least 30At most 4320Default
240
scheduledAtstringWhen to start: an ISO 8601 instant or a duration such as
PT2H, in the future and at most 365 days out. Left out, the sending starts straight away.3 to 64 characters
Returns
An Idempotency-Key replayed an earlier call. This is that broadcast, not a new one.
objectstring- One of
"broadcast" idstringThe durable handle,
brd_+ 24 hex.statusstringdraftis saved and not sent:POST /broadcasts/{id}/sendsends it.scheduledwaits forscheduledAt.queuedwaits for the sending to start.sendingis walking the audiences, or has finished walking them while copies are still waiting to go.sentmeans every copy handed over has been sent or settled.cancelledwas stopped byPOST /broadcasts/{id}/cancel.failedmeans the whole broadcast stopped: thefromaddress can no longer be sent from, the template stopped resolving, the plan ran out part way, the sending itself kept failing, or not one copy could be written, andlastErrorsays which.One of"draft""scheduled""queued""sending""sent""cancelled""failed"modestringThe mode of the key that created it. A broadcast made with a test key sends its copies the way any test send goes: accepted and marked sent, and delivered to nobody.
One of"live""test"sourcestringWhere it was started:
apifor a key,oauthfor a connected app,composerfor the app,mcpfor an assistant.One of"api""oauth""composer""mcp""ai""form""mail-app""booking"audienceIdsstring[]The audiences it was sent to, each once.
fromstringThe address every copy is sent from.
subjectstringThe subject as written, merge fields and all, so it reads the same for every copy. Empty when a template supplies the subject.
countsBroadcastCountslastErrorstringWhy the broadcast failed, or the most recent copy that could not be written and why. Null while nothing has gone wrong.
Can be nullscheduledAtstringWhen the sending is due to start. Null for a broadcast sent straight away.
Can be nullFormatdate-timestartedAtstringWhen the sending reached the first people. Null until then.
Can be nullFormatdate-timecompletedAtstringWhen the last person was reached and every copy had been written. Copies can still be waiting to go after it, which is why
statuscan readsendingwith this set.Can be nullFormatdate-timecancelledAtstring- Can be nullFormat
date-time createdAtstring- Format
date-time updatedAtstring- Format
date-time contentBroadcastContentreplayedbooleanTrue when an
Idempotency-Keyreplayed an earlier call, false for a new broadcast.
Accepted. The Location header names the broadcast; nothing has been sent yet.
objectstring- One of
"broadcast" idstringThe durable handle,
brd_+ 24 hex.statusstringdraftis saved and not sent:POST /broadcasts/{id}/sendsends it.scheduledwaits forscheduledAt.queuedwaits for the sending to start.sendingis walking the audiences, or has finished walking them while copies are still waiting to go.sentmeans every copy handed over has been sent or settled.cancelledwas stopped byPOST /broadcasts/{id}/cancel.failedmeans the whole broadcast stopped: thefromaddress can no longer be sent from, the template stopped resolving, the plan ran out part way, the sending itself kept failing, or not one copy could be written, andlastErrorsays which.One of"draft""scheduled""queued""sending""sent""cancelled""failed"modestringThe mode of the key that created it. A broadcast made with a test key sends its copies the way any test send goes: accepted and marked sent, and delivered to nobody.
One of"live""test"sourcestringWhere it was started:
apifor a key,oauthfor a connected app,composerfor the app,mcpfor an assistant.One of"api""oauth""composer""mcp""ai""form""mail-app""booking"audienceIdsstring[]The audiences it was sent to, each once.
fromstringThe address every copy is sent from.
subjectstringThe subject as written, merge fields and all, so it reads the same for every copy. Empty when a template supplies the subject.
countsBroadcastCountslastErrorstringWhy the broadcast failed, or the most recent copy that could not be written and why. Null while nothing has gone wrong.
Can be nullscheduledAtstringWhen the sending is due to start. Null for a broadcast sent straight away.
Can be nullFormatdate-timestartedAtstringWhen the sending reached the first people. Null until then.
Can be nullFormatdate-timecompletedAtstringWhen the last person was reached and every copy had been written. Copies can still be waiting to go after it, which is why
statuscan readsendingwith this set.Can be nullFormatdate-timecancelledAtstring- Can be nullFormat
date-time createdAtstring- Format
date-time updatedAtstring- Format
date-time contentBroadcastContentreplayedbooleanTrue when an
Idempotency-Keyreplayed an earlier call, false for a new broadcast.
Errors
- 403
insufficient_scopeunless the key holds bothemails:sendandaudiences:read, orfrom_address_forbiddenwhen the key may not send asfrom.- 404
audience_not_foundonaudienceIdswhen an id names no audience in this workspace. Nothing is written.- 409
domain_not_sendable: thefromdomain is known to this workspace but cannot sign mail yet, the same refusalPOST /emailsgives.- 422
no_recipientsonaudienceIdswhen the audiences are empty or everybody in them has unsubscribed or is suppressed.audience_is_everyoneonaudienceIdswhen one of them is All contacts, the built-in audience.invalid_parameterorunknown_parameteron a field that does not validate: no body,htmlortextalongsidetemplate, nosubjectwithout a template, more than 10 audiences or 8 tags, or ascheduledAtthat is not in the future or more than 365 days out.template_not_found,template_not_publishedand the other template refusals ontemplate.*, or a prop that does not fit the template ontemplate.props.<name>.- 429
send_quota_exceeded: the plan cannot cover a copy for every recipient this month. Nothing was written, and no broadcast is left behind.rate_limited: the key or app made more than 600 requests in 60 seconds. Wait for the seconds inRetry-After.
The errors every operation can return400401500Error catalog
Also available in
POST/broadcasts/preview
Count who a broadcast would reach
The numbers POST /broadcasts would work from, without sending anything or writing anything: how many people it would reach, how many are skipped because they have unsubscribed, and how many because their address is suppressed. A contact in several of the audiences counts once.
The count is taken at the moment of the call. Contacts who join or leave before the send starts change it.
Requires the audiences:read scope.
Request body
audienceIdsstring[]Required1 to 10 audience ids, the same list you would send.
1 to 10 itemsexcludeAudienceIdsstring[]Up to 10 audiences whose members are left out, even when they are also in one of
audienceIds, such as the customers who already bought. All contacts may be named here.Up to 10 itemssegmentIdstringA saved segment that narrows the audiences: only the contacts that match its conditions get a copy, such as the people who opened in the last 90 days. The conditions are read when the broadcast is sent or scheduled and kept with it, so editing the segment later changes nothing that is already on its way. Resending to the people who did not open leaves the segment out, because they already passed it.
1 to 64 characters
Returns
The counts. Nothing was sent.
Errors
- 404
audience_not_foundonaudienceIdswhen an id names no audience in this workspace.- 422
audience_is_everyoneonaudienceIdswhen one of them is All contacts, the built-in audience, which no broadcast can go to.invalid_parameteronaudienceIdswhen it is empty or holds more than 10 ids,unknown_parameterfor any other key in the body.
The errors every operation can return400401403429500Error catalog
Also available in
GET/broadcasts/analytics
Broadcast analytics across broadcasts
The numbers behind the Analytics tab of the Broadcasts page, in one request: how the live broadcasts sent inside a window did, added up and as a series cut to grain, plus one row per broadcast so they can be compared.
A copy counts when it was sent, or written if it has not gone yet, inside the window, and everything that happened to it afterwards counts with it, so an open today of a copy sent last week is in a 30 day window but not in a 1 day one. Test mode broadcasts are left out. totals and series cover the broadcasts in broadcastIds, or every one when it is left out, and broadcasts always lists every broadcast in the window. The series counts each person once, at the first time it happened to them.
A key limited to particular addresses or domains reads only broadcasts sent from an address or domain it holds, and the rest are left out as if they did not exist.
Requires the emails:read scope.
Query parameters
broadcastIdsstringComma separated broadcast ids, at most 50, that
totalsandseriesadd up. Leave it out for every broadcast in the window. A repeated id counts once, and one with no copy in the window adds nothing.Up to 4000 charactersdaysintegerHow far back to look. The window starts at the beginning of its first bucket in the offset you asked for, so the oldest bucket is a whole one, and ends now.
At least 1At most 1095Default30minutesintegerThe window in minutes, which wins over
dayswhen both are sent.At least 1At most 1576800grainstringHow wide one bucket is, and the shape of its key:
YYYY-MM-DDfor a day,YYYY-MM-DDTHHfor an hour,YYYY-MM-DDTHH:MMfor a minute.One of"minute""hour""day"Default"day"offsetMinutesintegerMinutes east of UTC to cut the buckets in. Pass
-new Date().getTimezoneOffset()for the local zone.At least -840At most 840Default0
Returns
The window, the totals, the series and every broadcast in the window.
Errors
- 422
invalid_parameteronbroadcastIdsfor more than 50 ids, ondays,minutesoroffsetMinutesout of range, or on an unknowngrain.
The errors every operation can return400401403404429500Error catalog
Also available in
GET/broadcasts/{id}
Retrieve a broadcast
One broadcast with counts read live from its copies, which makes this the call to poll while it sends. status settles on sent once every copy handed over has gone out or failed, and on failed or cancelled when it stopped early.
A key limited to particular addresses or domains reads only broadcasts sent from an address or domain it holds. Any other broadcast answers 404 broadcast_not_found, as if it did not exist.
Requires the emails:read scope.
Path parameters
idstringRequiredA
brd_id fromPOST /broadcastsorGET /broadcasts.
Returns
The broadcast.
Errors
- 404
broadcast_not_foundwhen the id names no broadcast in this workspace.
The errors every operation can return400401403422429500Error catalog
Also available in
PATCH/broadcasts/{id}
Update a draft or a scheduled broadcast
A partial update: a field left out keeps what it holds, and null clears replyTo, html, text, template or utm. Sending any of html, text or template replaces the body as a whole.
A draft takes every change and stays a draft. A scheduled broadcast takes changes until its sending starts, each checked the way POST /broadcasts checks a new one, and counts.recipients is counted again. scheduledAt moves a scheduled broadcast to another time. Any other broadcast answers 409 broadcast_not_editable.
A key limited to particular addresses or domains changes only broadcasts sent from an address or domain it holds.
Requires the emails:send and audiences:read scopes.
Path parameters
idstringRequiredA
brd_id fromPOST /broadcastsorGET /broadcasts.
Request body
audienceIdsstring[]The new audiences, replacing the old list.
Up to 10 itemsexcludeAudienceIdsstring[]Up to 10 audiences whose members are left out, even when they are also in one of
audienceIds, such as the customers who already bought. All contacts may be named here.Up to 10 itemssegmentIdstringA saved segment that narrows the audiences: only the contacts that match its conditions get a copy, such as the people who opened in the last 90 days. The conditions are read when the broadcast is sent or scheduled and kept with it, so editing the segment later changes nothing that is already on its way. Resending to the people who did not open leaves the segment out, because they already passed it. Null takes it away.
Can be null1 to 64 charactersfromstring | objectA new sender the key may send as.
emailstringRequired- Up to 320 characters
namestring- Up to 128 characters
replyTostring | objectWhere replies go. Null takes it away.
Can be nullemailstringRequired- Up to 320 characters
namestring- Up to 128 characters
subjectstringA new subject, with merge fields.
Up to 998 charactershtmlstringA new HTML body. Sending
html,textortemplatereplaces the body as a whole.Can be nullUp to 1000000 characterstextstringA new plain text body.
Can be nullUp to 1000000 characterstemplateobjectA stored template instead of
htmlandtext. Null takes it away.Can be nullidstringRequired- 1 to 128 characters
versioninteger- More than 0At most 100000
propsRecord<string, any>slotsRecord<string, any>
trackingobjectOpen and link tracking for every copy.
opensbooleanclicksboolean
tagsRecord<string, string>The new tags, replacing the old ones, up to 8.
utmobjectCampaign tags added to every http and https link in the body:
source,medium,campaign,termandcontentbecomeutm_sourceand the rest, so the visits show up in your web analytics. A link that already carries one keeps its own value, and the unsubscribe link never gets them. Values are 1 to 100 characters,campaignup to 200. Null takes them away.Can be nullsourcestring- 1 to 100 characters
mediumstring- 1 to 100 characters
campaignstring- 1 to 200 characters
termstring- 1 to 100 characters
contentstring- 1 to 100 characters
abTestobjectAn A/B test.
variantsholds 2 to 4 versions, each asubject, or a body ashtmland ortext, that replaces the broadcast's own, so{}keeps the broadcast as it is.testPercent(5 to 50, 20 unless set) of the people get a variant, split evenly between them, andmetric(opensunless set, orclicks) picks the winner oncewaitMinutes(30 to 4320, 240 unless set) have passed since the test went out. Everybody else then gets the winning variant. The rate counts the people who opened or clicked out of the copies each variant sent, a tie goes to the earlier variant, and with nothing to compare the first variant wins. A template broadcast can only vary the subject. Null takes it away.Can be nullvariantsobject[]Required- 2 to 4 items
subjectstring- 1 to 998 characters
htmlstring- 1 to 1000000 characters
textstring- 1 to 1000000 characters
testPercentinteger- At least 5At most 50Default
20 metricstring- One of
"opens""clicks"Default"opens" waitMinutesinteger- At least 30At most 4320Default
240
scheduledAtstringA new start for a scheduled broadcast, in the future and at most 365 days out. A draft refuses it: give the time to
POST /broadcasts/{id}/send.3 to 64 characters
Returns
The broadcast as it stands after the change, with its content.
Errors
- 403
from_address_forbiddenwhen the key may not send asfrom.- 404
broadcast_not_foundwhen the id names no broadcast in this workspace,audience_not_foundon an audience id.- 409
broadcast_not_editable: the broadcast is queued, sending or finished.stream_pausedwhile the broadcast lane of the workspace is paused.- 422
no_recipientswhen a scheduled broadcast would reach nobody,invalid_parameteronscheduledAtfor a draft, which is scheduled when it is sent, or on a field that does not validate.- 429
send_quota_exceeded: the plan cannot cover the scheduled broadcast after the change.rate_limited: the key or app made more than 600 requests in 60 seconds. Wait for the seconds inRetry-After.
The errors every operation can return400401500Error catalog
Also available in
GET/broadcasts/{id}/recipients
List the recipients of a broadcast
Everybody the broadcast went to, one row per copy, sorted by address: the copy id, its status, when it was sent and delivered, whether it bounced or was reported as spam, how often it was opened and clicked, and whether the person unsubscribed after it went out.
Opens and clicks leave out image proxies and link scanners, and stay 0 when the broadcast was sent with tracking off. Keyset paging: pass nextCursor back as cursor, with the same filter and q.
A key limited to particular addresses or domains reads only broadcasts sent from an address or domain it holds. Any other broadcast answers 404 broadcast_not_found, as if it did not exist.
Requires the emails:read scope.
Path parameters
idstringRequiredA
brd_id fromPOST /broadcastsorGET /broadcasts.
Query parameters
filterstringKeeps one group:
pending(still queued or sending),sent,delivered,opened,not_opened(sent and never opened),clicked,bounced,complained,failed(failed or cancelled) orunsubscribed.One of"pending""sent""delivered""opened""not_opened""clicked""bounced""complained""failed""unsubscribed"qstringSearches the address and the name, ignoring case.
Up to 200 characterslimitintegerRows per page, 1 to 200.
At least 1At most 200Default50cursorstringThe previous page's
nextCursor, passed back as it came. It is opaque: it holds where the last row sat in this list's order, so a row deleted or edited between pages never breaks the walk, and the next page starts at the first row that sorts after it. A value this list did not hand out is a 400invalid_cursor.
Returns
A page of recipients, by address.
Errors
- 404
broadcast_not_foundwhen the id names no broadcast in this workspace.
The errors every operation can return400401403422429500Error catalog
Also available in
- TypeScript
nextmail.broadcasts.listRecipients()nextmail.broadcasts.listAllRecipients()nextmail.broadcasts.iterateRecipients()- Python
broadcasts.list_recipients()broadcasts.list_all_recipients()broadcasts.iterate_recipients()- Ruby
broadcasts.list_recipientsbroadcasts.list_all_recipientsbroadcasts.iterate_recipients- PHP
broadcasts->listRecipientsbroadcasts->listAllRecipientsbroadcasts->iterateRecipients- Go
Broadcasts.ListRecipientsBroadcasts.ListAllRecipientsBroadcasts.IterateRecipients- Java
broadcasts().listRecipientsbroadcasts().listAllRecipientsbroadcasts().iterateRecipients- C#
Broadcasts.ListRecipientsAsyncBroadcasts.ListAllRecipientsAsyncBroadcasts.IterateRecipientsAsync- CLI
openemail broadcasts list-recipients- MCP
listBroadcastRecipients
GET/broadcasts/{id}/recipients/{emailId}
Retrieve one copy of a broadcast
One person's copy: the same row GET /broadcasts/{id}/recipients lists, plus the subject, HTML and text exactly as that person received them, with the merge fields filled in and their own unsubscribe link. The HTML is from before open and click tracking was added.
A key limited to particular addresses or domains reads only broadcasts sent from an address or domain it holds. Any other broadcast answers 404 broadcast_not_found, as if it did not exist.
Requires the emails:read scope.
Path parameters
idstringRequiredA
brd_id fromPOST /broadcastsorGET /broadcasts.emailIdstringRequiredThe
emailIdof the copy, from the recipients list.
Returns
The copy and its content.
Errors
- 404
broadcast_not_foundfor an unknown broadcast,recipient_not_foundfor a copy that is not part of it.
The errors every operation can return400401403422429500Error catalog
Also available in
GET/broadcasts/{id}/stats
Broadcast statistics
How the broadcast performed: copies sent, delivered, bounced, reported as spam and failed, and how many people opened, clicked and unsubscribed, as totals and as a series cut to grain. The series counts each person once, at the first time it happened to them, so it adds up to the totals.
Send days or minutes to also read what happened lately: window then counts the copies delivered, bounced, reported, opened, clicked and unsubscribed inside it, and series keeps only its buckets. totals always covers the whole broadcast.
A key limited to particular addresses or domains reads only broadcasts sent from an address or domain it holds. Any other broadcast answers 404 broadcast_not_found, as if it did not exist.
Requires the emails:read scope.
Path parameters
idstringRequiredA
brd_id fromPOST /broadcastsorGET /broadcasts.
Query parameters
grainstringBucket width of the series.
One of"minute""hour""day"Default"hour"offsetMinutesintegerMinutes east of UTC to cut the buckets in. Pass
-new Date().getTimezoneOffset()for the local zone.At least -840At most 840Default0daysintegerReads a window too: how far back it reaches. It starts at the beginning of its first
grainbucket and ends now. Leave it andminutesout for no window.At least 1At most 1095minutesintegerThe window in minutes, which wins over
dayswhen both are sent.At least 1At most 1576800
Returns
Totals, the window and the series.
Errors
- 404
broadcast_not_foundwhen the id names no broadcast in this workspace.- 422
invalid_parameterondays,minutesoroffsetMinutesout of range, or on an unknowngrain.
The errors every operation can return400401403429500Error catalog
Also available in
POST/broadcasts/{id}/cancel
Cancel a broadcast
Stops a broadcast that is scheduled, queued or sending, including one that has reached everybody while some copies are still waiting to go. Nobody else is added, and every copy still waiting to go is cancelled. A copy already being handed over finishes, and copies that have gone cannot be recalled, so counts.sent keeps them. No body.
Cancelling a cancelled broadcast answers it as it stands, so a retry is safe.
A key limited to particular addresses or domains cancels only broadcasts sent from an address or domain it holds. Any other broadcast answers 404 broadcast_not_found, as if it did not exist.
Requires the emails:send scope.
Path parameters
idstringRequiredA
brd_id fromPOST /broadcastsorGET /broadcasts.
Returns
The broadcast, now cancelled.
Errors
- 404
broadcast_not_foundwhen the id names no broadcast in this workspace.- 409
broadcast_not_cancellable: every copy has already gone out, or the broadcastfailed.
The errors every operation can return400401403422429500Error catalog
Also available in
POST/broadcasts/drafts
Save a broadcast draft
Saves a broadcast with status draft. Nothing is sent, nothing counts against the plan and the audiences may still be empty, so a draft can be written over several sittings. PATCH /broadcasts/{id} changes it, POST /broadcasts/{id}/send sends or schedules it, and GET /broadcasts/{id} returns what it holds in content.
The body takes the fields POST /broadcasts takes, except scheduledAt, and only from is required. The sender, the audiences and a template are checked as they are saved.
Requires the emails:send and audiences:read scopes.
Request body
audienceIdsstring[]Up to 10 audience ids. May be empty in a draft, but not when it is sent.
Up to 10 itemsDefault[]excludeAudienceIdsstring[]Up to 10 audiences whose members are left out, even when they are also in one of
audienceIds, such as the customers who already bought. All contacts may be named here.Up to 10 itemssegmentIdstringA saved segment that narrows the audiences: only the contacts that match its conditions get a copy, such as the people who opened in the last 90 days. The conditions are read when the broadcast is sent or scheduled and kept with it, so editing the segment later changes nothing that is already on its way. Resending to the people who did not open leaves the segment out, because they already passed it.
1 to 64 charactersfromstring | objectRequiredThe sender, an address the key may send as, bare or with a name.
emailstringRequired- Up to 320 characters
namestring- Up to 128 characters
replyTostring | objectWhere replies go, the same for every copy.
emailstringRequired- Up to 320 characters
namestring- Up to 128 characters
subjectstringAt most 998 characters, with merge fields. Needed before sending unless a template supplies it.
Up to 998 charactersDefault""htmlstringHTML body, at most 1,000,000 characters, with merge fields.
Up to 1000000 characterstextstringPlain text body, at most 1,000,000 characters, with merge fields.
Up to 1000000 characterstemplateobjectA stored template instead of
htmlandtext, never beside them.idstringRequired- 1 to 128 characters
versioninteger- More than 0At most 100000
propsRecord<string, any>slotsRecord<string, any>
trackingobjectOpen and link tracking for every copy.
opensbooleanclicksboolean
tagsRecord<string, string>Up to 8 tags every copy carries.
Default{}utmobjectCampaign tags added to every http and https link in the body:
source,medium,campaign,termandcontentbecomeutm_sourceand the rest, so the visits show up in your web analytics. A link that already carries one keeps its own value, and the unsubscribe link never gets them. Values are 1 to 100 characters,campaignup to 200.sourcestring- 1 to 100 characters
mediumstring- 1 to 100 characters
campaignstring- 1 to 200 characters
termstring- 1 to 100 characters
contentstring- 1 to 100 characters
abTestobjectAn A/B test.
variantsholds 2 to 4 versions, each asubject, or a body ashtmland ortext, that replaces the broadcast's own, so{}keeps the broadcast as it is.testPercent(5 to 50, 20 unless set) of the people get a variant, split evenly between them, andmetric(opensunless set, orclicks) picks the winner oncewaitMinutes(30 to 4320, 240 unless set) have passed since the test went out. Everybody else then gets the winning variant. The rate counts the people who opened or clicked out of the copies each variant sent, a tie goes to the earlier variant, and with nothing to compare the first variant wins. A template broadcast can only vary the subject.variantsobject[]Required- 2 to 4 items
subjectstring- 1 to 998 characters
htmlstring- 1 to 1000000 characters
textstring- 1 to 1000000 characters
testPercentinteger- At least 5At most 50Default
20 metricstring- One of
"opens""clicks"Default"opens" waitMinutesinteger- At least 30At most 4320Default
240
Returns
The draft, with its content. The Location header names it. Nothing was sent.
Errors
- 403
insufficient_scopeunless the key holds bothemails:sendandaudiences:read, orfrom_address_forbiddenwhen the key may not send asfrom.- 404
audience_not_foundonaudienceIdsorexcludeAudienceIds.- 422
audience_is_everyonewhenaudienceIdsnames All contacts,invalid_parameterorunknown_parameteron a field that does not validate, and the template refusals ontemplate.*.
The errors every operation can return400401429500Error catalog
Also available in
POST/broadcasts/test
Send a test of a broadcast
Sends one copy of a broadcast to up to 5 addresses, to read it before it goes out. Without to it goes to the account address of the person the key or app acts for, the workspace owner for an API key. The merge fields are filled from the contact that has the address when there is one and from a sample name otherwise, the subject starts with [Test], the unsubscribe footer is added as it would be and its link does nothing. Opens and clicks are not tracked, and utm is applied to the links.
No broadcast is created and nobody joins an audience. Each copy counts as one send.
Requires the emails:send scope.
Request body
fromstring | objectRequiredThe sender, an address the key may send as.
emailstringRequired- Up to 320 characters
namestring- Up to 128 characters
replyTostring | objectWhere replies go.
emailstringRequired- Up to 320 characters
namestring- Up to 128 characters
subjectstringRequired unless a template supplies it, with merge fields.
Up to 998 charactersDefault""htmlstringHTML body with merge fields.
Up to 1000000 characterstextstringPlain text body with merge fields.
Up to 1000000 characterstemplateobjectA stored template instead of
htmlandtext.idstringRequired- 1 to 128 characters
versioninteger- More than 0At most 100000
propsRecord<string, any>slotsRecord<string, any>
utmobjectCampaign tags added to every http and https link in the body:
source,medium,campaign,termandcontentbecomeutm_sourceand the rest, so the visits show up in your web analytics. A link that already carries one keeps its own value, and the unsubscribe link never gets them. Values are 1 to 100 characters,campaignup to 200.sourcestring- 1 to 100 characters
mediumstring- 1 to 100 characters
campaignstring- 1 to 200 characters
termstring- 1 to 100 characters
contentstring- 1 to 100 characters
to(string | object)[]1 to 5 addresses. Left out, the test goes to the account address of the person the key or app acts for.
1 to 5 itemsemailstringRequired- Up to 320 characters
namestring- Up to 128 characters
Returns
The copies that were sent.
Errors
- 403
from_address_forbiddenwhen the key may not send asfrom.- 409
domain_not_sendable: thefromdomain cannot sign mail yet.- 422
invalid_parameteron a field that does not validate: no body,htmlortextbesidetemplate, nosubjectwithout a template, or more than 5 addresses into. The template refusals ontemplate.*.- 429
send_quota_exceeded: the plan has no sends left this month.rate_limited: the key or app made more than 600 requests in 60 seconds. Wait for the seconds inRetry-After.
The errors every operation can return400401404500Error catalog
Also available in
POST/broadcasts/{id}/send
Send a draft
Turns a draft into a broadcast that goes out: queued straight away, or scheduled with scheduledAt. The draft is checked the way POST /broadcasts checks a new broadcast: it needs an audience, a body, a subject or a template that supplies one, somebody to reach and room in the plan for every copy. A broadcast that is not a draft answers 409 broadcast_not_draft, so a repeated call never sends twice. The body is optional.
Requires the emails:send and audiences:read scopes.
Path parameters
idstringRequiredA
brd_id fromPOST /broadcastsorGET /broadcasts.
Request body
scheduledAtstringWhen to start: an ISO 8601 instant or a duration such as
PT2H, in the future and at most 365 days out. Left out, the sending starts straight away.3 to 64 characters
Returns
Accepted. The broadcast is queued or scheduled, and nothing has been sent yet.
Errors
- 403
from_address_forbiddenwhen the key may no longer send as the draft'sfrom.- 404
broadcast_not_found, oraudience_not_foundwhen an audience of the draft is gone.- 409
broadcast_not_draft,stream_pausedwhile the broadcast lane is paused, ordomain_not_sendable.- 422
no_recipientswhen the draft has no audience or nobody in it can be sent to,invalid_parameterwhen it has no body or no subject, or on ascheduledAtthat is not in the future or more than 365 days out.- 429
send_quota_exceeded: the plan cannot cover a copy for every recipient this month.rate_limited: the key or app made more than 600 requests in 60 seconds. Wait for the seconds inRetry-After.
The errors every operation can return400401500Error catalog
Also available in
POST/broadcasts/{id}/duplicate
Duplicate a broadcast
Copies any broadcast into a new draft: the same sender, audiences, left-out audiences, subject, body or template, tracking, tags and campaign tags, without the time it was scheduled for. The original is not changed and nothing is sent. No body.
Requires the emails:send and audiences:read scopes.
Path parameters
idstringRequiredA
brd_id fromPOST /broadcastsorGET /broadcasts.
Returns
The new draft. The Location header names it.
Errors
- 403
from_address_forbiddenwhen the key may not send as the originalfrom.- 404
broadcast_not_found, oraudience_not_foundwhen an audience of the original is gone.- 422
The template refusals on
template.*when the original template no longer resolves.
The errors every operation can return400401429500Error catalog
Also available in
POST/broadcasts/{id}/resend
Resend to the people who did not open
Creates a new broadcast with the same content for the people the first one reached and who have not opened it, optionally under a new subject. Somebody who has unsubscribed since, or whose address is now suppressed, is skipped. The new broadcast names the first in content.resendOf and counts against the plan like any send. The first broadcast has to be sent and to have tracked opens, or the call answers 409 resend_unavailable. The body is optional.
Opens are counted from the tracking pixel, so a person whose mail app blocks images can look like they never opened.
Requires the emails:send and audiences:read scopes.
Path parameters
idstringRequiredA
brd_id fromPOST /broadcastsorGET /broadcasts.
Request body
subjectstringA new subject for the second try, with merge fields. Left out, the first subject is used.
1 to 998 charactersscheduledAtstringWhen to start, in the future and at most 365 days out. Left out, the sending starts straight away.
3 to 64 characters
Returns
Accepted. The new broadcast, queued or scheduled. The Location header names it.
Errors
- 404
broadcast_not_foundwhen the id names no broadcast in this workspace.- 409
resend_unavailable: the broadcast has not finished going out or did not track opens.stream_pausedwhile the broadcast lane is paused.- 422
no_recipientswhen everybody it reached has opened it.- 429
send_quota_exceeded: the plan cannot cover a copy for every recipient this month.rate_limited: the key or app made more than 600 requests in 60 seconds. Wait for the seconds inRetry-After.
The errors every operation can return400401403500Error catalog
Also available in
Objects
Broadcastobject
objectstring- One of
"broadcast" idstringThe durable handle,
brd_+ 24 hex.statusstringdraftis saved and not sent:POST /broadcasts/{id}/sendsends it.scheduledwaits forscheduledAt.queuedwaits for the sending to start.sendingis walking the audiences, or has finished walking them while copies are still waiting to go.sentmeans every copy handed over has been sent or settled.cancelledwas stopped byPOST /broadcasts/{id}/cancel.failedmeans the whole broadcast stopped: thefromaddress can no longer be sent from, the template stopped resolving, the plan ran out part way, the sending itself kept failing, or not one copy could be written, andlastErrorsays which.One of"draft""scheduled""queued""sending""sent""cancelled""failed"modestringThe mode of the key that created it. A broadcast made with a test key sends its copies the way any test send goes: accepted and marked sent, and delivered to nobody.
One of"live""test"sourcestringWhere it was started:
apifor a key,oauthfor a connected app,composerfor the app,mcpfor an assistant.One of"api""oauth""composer""mcp""ai""form""mail-app""booking"audienceIdsstring[]The audiences it was sent to, each once.
fromstringThe address every copy is sent from.
subjectstringThe subject as written, merge fields and all, so it reads the same for every copy. Empty when a template supplies the subject.
countsBroadcastCountslastErrorstringWhy the broadcast failed, or the most recent copy that could not be written and why. Null while nothing has gone wrong.
Can be nullscheduledAtstringWhen the sending is due to start. Null for a broadcast sent straight away.
Can be nullFormatdate-timestartedAtstringWhen the sending reached the first people. Null until then.
Can be nullFormatdate-timecompletedAtstringWhen the last person was reached and every copy had been written. Copies can still be waiting to go after it, which is why
statuscan readsendingwith this set.Can be nullFormatdate-timecancelledAtstring- Can be nullFormat
date-time createdAtstring- Format
date-time updatedAtstring- Format
date-time contentBroadcastContent
BroadcastAnalyticsobject
objectstring- One of
"broadcast_analytics" sincestringThe start of the window, floored to the start of its first bucket in the local time of
offsetMinutes.Formatdate-timeuntilstringThe end of the window, the moment of the read.
Formatdate-timegrainstring- One of
"minute""hour""day" offsetMinutesintegerThe offset the buckets were cut in, as sent or 0.
broadcastIdsstring[]The ids
totalsandseriescover, each once. Empty means every broadcast in the window.totalsobjectAdded up over the copies of the broadcasts in
broadcastIdsthat were sent inside the window.opened,clickedandunsubscribedcount people;opensandclickscount events.broadcastsintegerHow many broadcasts those copies belong to.
recipientsintegerpendingintegerCopies still queued, scheduled or sending.
sentintegerdeliveredintegerbouncedintegercomplainedintegerfailedintegerCopies that failed or were cancelled.
openedintegerclickedintegerunsubscribedintegeropensintegerclicksinteger
seriesobject[]SPARSE, oldest first: one bucket per
grainin which something happened to those copies, each counted once, at the first time it happened.bucketstringYYYY-MM-DD,YYYY-MM-DDTHHorYYYY-MM-DDTHH:MM, in the offset asked for.sentintegerdeliveredintegeropenedintegerclickedintegerunsubscribedinteger
broadcastsobject[]Every broadcast with a copy sent inside the window, newest first, whatever
broadcastIdspicks, each with the same counts over its copies in the window. Use it to compare broadcasts or to pick ids.idstringsubjectstringstatusstring- One of
"draft""scheduled""queued""sending""sent""cancelled""failed" sentAtstringWhen it started sending, or when it was created if it has not.
Formatdate-timerecipientsintegerpendingintegerCopies still queued, scheduled or sending.
sentintegerdeliveredintegerbouncedintegercomplainedintegerfailedintegerCopies that failed or were cancelled.
openedintegerclickedintegerunsubscribedintegeropensintegerclicksinteger
BroadcastContentobject
subjectstringRequiredThe subject as written, merge fields and all.
htmlstringRequiredThe HTML body as written, before the unsubscribe footer is added.
Can be nulltextstringRequiredThe plain text body as written.
Can be nulltemplateobjectRequiredThe stored template the body comes from, with the props and slots it was given.
Can be nullidstringversionintegerpropsobjectslotsobject
replyTostringRequiredWhere replies go.
Can be nulltrackingobjectRequiredOpen and link tracking for every copy.
Can be nullopensbooleanclicksboolean
tagsRecord<string, string>RequiredexcludeAudienceIdsstring[]RequiredThe audiences whose members are left out.
segmentIdstringRequiredThe saved segment that narrows the audiences, or null.
Can be nullutmobjectRequiredThe campaign tags added to the links.
Can be nullsourcestring- 1 to 100 characters
mediumstring- 1 to 100 characters
campaignstring- 1 to 200 characters
termstring- 1 to 100 characters
contentstring- 1 to 100 characters
abTestobjectRequiredThe A/B test, or null. Beside the test as it was asked for,
phasesays where it stands:testingwhile the variants go out,waitinguntildecidesAt, andwinneroncewinnernames the variant everybody else gets.GET /broadcasts/{id}/statsreturns how each variant did.Can be nullvariantsobject[]Required- 2 to 4 items
subjectstring- 1 to 998 characters
htmlstring- 1 to 1000000 characters
textstring- 1 to 1000000 characters
testPercentinteger- At least 5At most 50Default
20 metricstring- One of
"opens""clicks"Default"opens" waitMinutesinteger- At least 30At most 4320Default
240 phasestringNull until the sending starts.
Can be nullOne of"testing""waiting""winner"winnerstringThe id of the winning variant,
atod, once it is picked.Can be nulldecidesAtstringWhile
waiting, when the winner is picked.Can be nullFormatdate-timedecidedAtstringWhen the winner was picked.
Can be nullFormatdate-time
resendOfstringRequiredFor a broadcast made by
POST /broadcasts/{id}/resend, the broadcast it sends again to the people who did not open it.Can be null
BroadcastCountsobject
Where the broadcast stands. The first four are kept by the sending itself; the last five are counted live from the copies, by the send status each one has now.
recipientsintegerThe estimate taken when the broadcast was created: the people it was expected to reach. It does not move afterwards, so contacts who join or leave while it sends make
createddiffer from it.createdintegerCopies written so far, one per person reached. Each is an ordinary email with its own
msg_id.skippedintegerPeople passed over while sending because their address was on the suppression list by the time the sending reached them.
failedToQueueintegerPeople whose copy could not be written at all.
lastErroron the broadcast names the most recent one and why.queuedintegerCopies waiting to be sent.
sendingintegerCopies being handed over right now.
sentintegerCopies that went out.
failedintegerCopies whose send failed.
GET /emails/{id}on one says why.cancelledintegerCopies a cancel stopped before they went.
BroadcastListobject
objectstring- One of
"list" dataBroadcast[]hasMorebooleanTrue when another page follows. Pass
nextCursorback ascursorto read it.nextCursorstringThe id of the last row on this page, or null on the last page.
Can be null
BroadcastPreviewobject
objectstring- One of
"broadcast_preview" audienceIdsstring[]The audiences as sent.
excludeAudienceIdsstring[]The audiences whose members were left out, as sent, or empty.
segmentIdstringThe segment the counts were narrowed to, as sent, or null.
Can be nullrecipientsintegerThe people a broadcast to these audiences would reach now. A contact in several of them counts once.
unsubscribedintegerContacts in these audiences who would be skipped because they have unsubscribed from every one of them they are in.
suppressedintegerSubscribed contacts who would be skipped because their address is on the suppression list after a bounce or a complaint, or because somebody added it there.
BroadcastRecipientobject
objectstring- One of
"broadcast_recipient" emailIdstringThe
msg_id of this person's copy.GET /emails/{id}reads it as a sent email.contactIdstringThe contact it went to, null if deleted since.
Can be nullemailstringThe address the copy went to.
namestring- Can be null
statusstringThe status of the copy on the send log:
queued,scheduled,sending,sent,bounced,failedorcancelled.sentAtstring- Can be nullFormat
date-time deliveredAtstringWhen the receiving server accepted it, the first
email.delivered.Can be nullFormatdate-timebouncedAtstringWhen it bounced, the first
email.bounced.Can be nullFormatdate-timecomplainedAtstringWhen the person reported it as spam, the first
email.complained.Can be nullFormatdate-timefailurestringWhy the copy failed, when it did.
Can be nullopensintegerOpens recorded, without the ones image proxies and scanners make. 0 when tracking was off.
firstOpenAtstring- Can be nullFormat
date-time clicksintegerClicks recorded on tracked links, without scanners.
firstClickAtstring- Can be nullFormat
date-time unsubscribedAtstringWhen this person unsubscribed from one of the broadcast's audiences after it was sent, through its link or otherwise.
Can be nullFormatdate-time
BroadcastRecipientContentobject
objectstring- One of
"broadcast_recipient" emailIdstringThe
msg_id of this person's copy.GET /emails/{id}reads it as a sent email.contactIdstringThe contact it went to, null if deleted since.
Can be nullemailstringThe address the copy went to.
namestring- Can be null
statusstringThe status of the copy on the send log:
queued,scheduled,sending,sent,bounced,failedorcancelled.sentAtstring- Can be nullFormat
date-time deliveredAtstringWhen the receiving server accepted it, the first
email.delivered.Can be nullFormatdate-timebouncedAtstringWhen it bounced, the first
email.bounced.Can be nullFormatdate-timecomplainedAtstringWhen the person reported it as spam, the first
email.complained.Can be nullFormatdate-timefailurestringWhy the copy failed, when it did.
Can be nullopensintegerOpens recorded, without the ones image proxies and scanners make. 0 when tracking was off.
firstOpenAtstring- Can be nullFormat
date-time clicksintegerClicks recorded on tracked links, without scanners.
firstClickAtstring- Can be nullFormat
date-time unsubscribedAtstringWhen this person unsubscribed from one of the broadcast's audiences after it was sent, through its link or otherwise.
Can be nullFormatdate-timesubjectstringThe subject as this person got it, merge fields filled in.
htmlstringThe HTML as this person got it, before open and click tracking was added.
Can be nulltextstring- Can be null
BroadcastRecipientListobject
objectstring- One of
"list" hasMorebooleanTrue when another page follows. Pass
nextCursorback ascursorto read it.nextCursorstringAn opaque cursor for the next page, or null on the last page. Pass it back unchanged.
Can be null
BroadcastStatsobject
objectstring- One of
"broadcast_stats" broadcastIdstringgrainstring- One of
"minute""hour""day" totalsobjectCounts over every copy.
opened,clickedandunsubscribedcount people;opensandclickscount events.recipientsintegerpendingintegerCopies still queued, scheduled or sending.
sentintegerdeliveredintegerbouncedintegercomplainedintegerfailedintegerCopies that failed or were cancelled.
openedintegerclickedintegerunsubscribedintegeropensintegerclicksinteger
windowobjectNull unless
daysorminuteswas sent. Each count is the copies whose first such event fell inside the window, so it tells you what changed lately, whiletotalskeeps the whole send.Can be nullsincestringThe start of the window, floored to the start of its first
grainbucket in the offset asked for. It ends now.Formatdate-timedeliveredintegerbouncedintegercomplainedintegeropenedintegerclickedintegerunsubscribedinteger
seriesobject[]SPARSE, oldest first: one bucket per
grainin which something happened. Each counts people by the first time it happened to them. With a window, only the buckets inside it.bucketstringYYYY-MM-DD,YYYY-MM-DDTHHorYYYY-MM-DDTHH:MM, in the offset asked for.deliveredintegeropenedintegerclickedintegerunsubscribedinteger
linksobject[]The 10 links clicked most, the most clicked first. Copies sent without link tracking have none.
urlstringThe address the link points to.
labelstringThe text of the link, when it had any.
Can be nullclicksintegerClicks on it, every time it was clicked.
peopleintegerThe people who clicked it at least once.
clientsobject[]The 8 mail clients people opened the copies in, the most used first, from the opens a person made, not the ones a privacy proxy made.
clientstringSuch as Gmail or Apple Mail, or null when it could not be told.
Can be nullpeopleintegeropensinteger
countriesobject[]The 10 countries the copies were opened from, the most first, as ISO 3166 codes.
countrystringpeopleinteger
abTestobjectNull unless the broadcast runs an A/B test. Each variant counts the copies it sent in the test and the people who opened or clicked one of them, so the rates can be compared before and after the winner is picked.
Can be nullmetricstring- One of
"opens""clicks" winnerstringThe winning variant, or null until it is picked.
Can be nullvariantsobject[]idstringatod, in the order ofabTest.variants.subjectstringThe subject of the variant, or null when it keeps the broadcast's own.
Can be nullsentintegeropenedintegerclickedinteger
BroadcastTestobject
objectstringRequired- One of
"broadcast_test" emailIdsstring[]RequiredThe
msg_id of each copy, in the order ofto.tostring[]RequiredThe addresses, lower-cased.