Mailings
This page is the API reference for developers reading or writing marketing mailings.
The Mailings app holds one planned send of one marketing mail to one audience under one subscription type. A new mailing is a draft. It can be scheduled only when its checklist has no error (warnings do not block), and then the send pipeline reads the audience in pages, asks the Marketing consents app who may receive it, drops recipients held back as graymail, and hands the batches to the messaging service. The Audiences app supplies the audience. The app keeps the figures of each mailing (recipient outcomes, opens, clicks, unsubscribes, complaints and revenue) and answers them for the mailing and the sending health of the last 30 days.
Known limit: the messaging service does not yet accept the recipient batches a mailing hands over, so a scheduled mailing reaches nobody for now. What happens next depends on the error. A network error, a 429 or a 5xx from the messaging service is treated as temporary: the mailing stays sending, the send run retries, and after 12 failed runs it ends failed. Any other error status fails the mailing on the first run, with a failure_reason such as sequencer_refused:404. A mailing scheduled to send at once shows the same failure in the run field of its schedule response. Test sends and previews work, and they are the way to check a mailing until this is lifted.
Objects
| Object | What it holds |
|---|---|
| Mailing | The name, subject, preview_text, sender, sender_name, reply_to, audience_id, exclude_audience_ids, subscription_type, template_key, voucher_batch_id, send_at, timezone_mode, graymail and graymail_sends, campaign_ref, the state and the list folder, and the counters such as recipients_count, sent_count and revenue, and the figures open_rate_percent, click_rate_percent and unsubscribed_count (read-only, see below), and the six trash fields. |
| Recipient | One row per audience member of a mailing, with its outcome (queued, sent, ineligible, graymail, suppressed, invalid or excluded). |
| Stats | The figures of one mailing: deliveries, bounces, opens, clicks and revenue. |
| Click | One clicked link of a mailing, with its clicks and unique clickers. |
| Engagement | One announcement from the messaging service that the app recorded for a mailing. Read only. |
| Variant | An A/B variant of a mailing. Reserved for a later version; the list is always empty in this one. |
A mailing has one state: draft, scheduled, sending, sent, cancelled or failed. The folder is the list view it sits in: drafts, scheduled, sent or archived. A mailing that is in the trash is left out of every view until it is restored.
Base path: https://api.revenexx.com/v1/mailings.
Scopes
A key calls these routes with the capability key of each route. The App's manifest names one per operation, in the form mailings.<group>.<operation>, and the API keys page explains that a key holds capability keys or a namespace such as mailings.*. The scope names are listed in the tables below. A call that needs a scope the key does not hold is refused with 403.
Mailings
| Operation | Scope | What it does |
|---|---|---|
GET /v1/mailings/mailings | mailings.mailings.list | Lists the mailings of the tenant. The trash is left out unless trashed asks for it. |
POST /v1/mailings/mailings | mailings.mailings.create | Writes a mailing down as a draft. |
GET /v1/mailings/mailings/{id} | mailings.mailings.get | Reads one mailing. |
PUT /v1/mailings/mailings/{id} | mailings.mailings.update | Changes a mailing. |
DELETE /v1/mailings/mailings/{id} | mailings.mailings.delete | Moves a mailing into the trash. A second DELETE on the same mailing deletes it for good, and a storefront contact is refused that second call with 403. |
POST /v1/mailings/mailings/trash/empty | mailings.mailings.empty-trash | Deletes every mailing in the trash for good. |
POST /v1/mailings/mailings/trash/purge | mailings.mailings.purge | Deletes the mailings that have been in the trash longer than the tenant's trash retention. It is the nightly purge, callable by hand. |
- List filters:
folder(drafts,scheduled,sentorarchived),state,campaign_ref,audience_id,subscription_type,template_key,starter,timezone_mode,duplicated_from_id,id, andtrashed(exclude,onlyorinclude).limittakes 1 to 200 (default 50), withoffsetandorder(a column, optionally.ascor.desc). - Create body: required
name. Every other field is optional.senderandsender_namecome from the market settings named in theX-Revenexx-Marketheader, or from the tenant settings.starterisblank(default),simple,newsletterorpromotion.timezone_modeistenant(default: everybody getssend_atat the same moment) orrecipient(send_atis read as wall-clock time in each recipient market time zone).graymailis on by default, andgraymail_sendstakes 1 to 100.subjectandpreview_textare stored as given: the checklist fails a subject over 150 characters and warns on a preview text over 200.exclude_audience_idstakes at most 10 ids. Create answers400for asenderorreply_tothat is not an email address, ids that are not UUIDs, a currency that is not three letters, and an audience that is both sent to and excluded. - Figures on a mailing: read-only, mirrored from its statistics. A value sent for them on a create or update is dropped.
open_rate_percent(number): unique human opens divided by deliveries, 0 to 100.click_rate_percent(number): unique clicks divided by deliveries, 0 to 100.unsubscribed_count(integer): recipients who unsubscribed through this mailing.
- Update: a draft changes freely, and so does a cancelled or failed mailing that nobody received (
sent_countis 0). In any other state onlyname,campaign_refandmetadatachange. A content change is refused with409andmailing_locked, withdetails.fieldsnaming the fields. - Delete: only a mailing that nobody received (
sent_countis 0) can go into the trash. Any other mailing is refused with409andtrash_blocked, its blocker namingmailing_sent: cancel a scheduled or sending mailing first, and archive one that reached recipients. A mailing in the trash counts nowhere until it is restored. - Empty trash and purge: a call from a storefront contact is
403withpurge_not_allowed. One empty-trash call handles at most 1000 trashed rows. A mailing that something still blocks stays in the trash, and the answer names it with its reason. The purge deletes nothing when the retention cannot be read. - Errors on the mailing routes:
404when no mailing has the id.409within_trashwhen a mailing in the trash is changed, duplicated, archived, scheduled, cancelled or test-sent: restore it first. Reads, the checklist, reach, preview and the figures still answer for it. Restoring a mailing that is not in the trash is409withnot_in_trash.
Lifecycle
| Operation | Scope | What it does |
|---|---|---|
POST /v1/mailings/mailings/{id}/restore | mailings.mailings.restore | Takes a mailing back out of the trash, in the state it was in. |
POST /v1/mailings/mailings/{id}/duplicate | mailings.mailings.duplicate | Copies a mailing into a new draft. Any mailing outside the trash can be copied, sent ones included. The copy keeps the content, audience and settings, drops the send time and the campaign, and is named <name> (Kopie). |
POST /v1/mailings/mailings/{id}/archive | mailings.mailings.archive | Moves a mailing to the archive. |
POST /v1/mailings/mailings/{id}/unarchive | mailings.mailings.unarchive | Takes a mailing out of the archive. |
GET /v1/mailings/mailings/{id}/checklist | mailings.mailings.checklist | Reads what must be true before the mailing may be scheduled. |
GET /v1/mailings/mailings/{id}/reach | mailings.mailings.reach | Reads how many people the mailing would reach. |
POST /v1/mailings/mailings/{id}/schedule | mailings.mailings.schedule | Runs the checklist and schedules the mailing. |
POST /v1/mailings/mailings/{id}/cancel | mailings.mailings.cancel | Cancels a scheduled or sending mailing. |
POST /v1/mailings/mailings/{id}/preview | mailings.mailings.preview | Renders the mailing as one recipient sees it. Nothing is sent. A voucher block shows a fixed sample voucher code instead of drawing a real one from the batch. |
POST /v1/mailings/mailings/{id}/test | mailings.mailings.test | Sends the mailing to colleagues as a test. |
- Archive: a scheduled or sending mailing is refused with
409andmailing_active. Cancel it first. A sent mailing can be archived, and it comes back with unarchive. - Checklist: each item has
ok, aseverity(errororwarning), astate(ok,warningorerror), a label, the problem as a sentence, and where to put it right. Only errors block a schedule.readyis true when no error stands, and the answer lists the failing items byerrorsandwarnings. The text followsAccept-Language, and German is the default unless English is asked for. The items aresubject,preview_text,sender,audience,subscription_type,template,footer_address,unsubscribe,links,alt_texts,voucher_batchandsend_time.- Errors: a missing subject (or one over 150 characters), sender, audience, subscription type, template, postal address or unsubscribe link; a link that leads nowhere; a send time in the past; a voucher block without a voucher batch, or a batch that is gone or cannot be read; and any check the other app could not answer.
- Warnings: a missing or over-long (over 200 characters) preview text, a missing alt text, an audience with no members right now, and a voucher batch named for a template that has no voucher block.
- Reach: the audience member and eligible counts, the excluded audiences, and
held_back_at_most, an upper bound on how many addresses graymail protection would hold back. It counts engagement rows across the whole tenant that are at or over the threshold, not only the rows of this audience. - Schedule body:
send_at(an ISO time, ornow,nullor""to send at once; left out, the mailing's ownsend_atholds),start(falseleaves even a send-at-once mailing to the next pipeline run) andtimezone_mode(tenantorrecipient). - Schedule errors:
409withchecklist_failedand the items when an error stands.409withnot_schedulablewhen the mailing is scheduled, sending or sent, or a cancelled or failed mailing that reached recipients (sent_countabove 0).409within_trashwhen it is in the trash.400whensend_atis not a time ortimezone_modeis nottenantorrecipient. - Cancel: nothing more is handed to the messaging service. Recipients already handed over keep their mail.
409withnot_cancellablewhen the mailing is not scheduled or sending, andstate_changedwhen it changed while the call ran. - Preview body:
market(the market to price and render for),locale,device(desktopormobile, a label only),contact_id,email(a placeholder address by default),first_nameandlast_name. Products are priced for the market named, and the footer is that market's. Nothing is sent. Errors:409withtemplate_missingwhen there is no template or its key is unknown,502withsequencer_unavailablewhen the template list cannot be read, and502withpreview_failedwhen rendering fails. - Test body:
recipients, at most 10 addresses, as a list or as a string separated by commas, semicolons or spaces. Without it the test recipients from the app settings are used.marketandlocaleare optional. Each address is sent on its own: one that fails does not fail the call, and the answer lists each address withsenttrue or false, plus the number sent. An address that was sent carries amessage_idand noreason; an address that failed carries areason. The template receives a[Test]subject prefix in its data. When the mailing names a voucher batch, a fixed sample voucher code is used; no code is drawn from the batch. The test counts in no figure. Errors:400with no code when there are more than 10 recipients,400withno_test_recipientsorinvalid_address(details.invalidlists the addresses),409withtemplate_missingorin_trash, and502withsequencer_unavailable.
Statistics and analysis
| Operation | Scope | What it does |
|---|---|---|
GET /v1/mailings/mailings/{id}/stats | mailings.analysis.stats | Reads what one mailing achieved. |
GET /v1/mailings/mailings/{id}/clicks | mailings.analysis.clicks | Reads the click map of one mailing. |
GET /v1/mailings/mailings/{id}/timeline | mailings.analysis.timeline | Reads the opens and clicks of one mailing per day. |
GET /v1/mailings/stats | mailings.analysis.list-stats | Lists the figures of mailings. |
GET /v1/mailings/stats/{id} | mailings.analysis.get-stats | Reads one figures row. |
POST /v1/mailings/stats/sweep | mailings.analysis.sweep | Brings the figures of the last 30 days up to date. It is the hourly job, callable by hand. |
GET /v1/mailings/clicks | mailings.analysis.list-clicks | Lists the clicked links of mailings. |
GET /v1/mailings/clicks/{id} | mailings.analysis.get-click | Reads one clicked link. |
GET /v1/mailings/engagements | mailings.analysis.list-engagements | Lists the announcements recorded for mailings. Read only. |
GET /v1/mailings/engagements/{id} | mailings.analysis.get-engagement | Reads one recorded announcement. |
- Stats: the recipient outcomes, deliveries, bounces, opens by people and by machines apart, clicks, click rate, click-to-open, unsubscribes, complaints and revenue. The open and click rates use unique clicks and human opens; the bounce, unsubscribe and complaint rates use their own counts. Machine opens are the opens a mail client or a bot makes by itself, for example when it prefetches the pixel.
- Click map: every clicked link with its clicks, unique clickers and share of all clicks, the most clicked first.
- Timeline: human opens and clicks per day in the tenant time zone, at most the latest 60 days. Machine opens are left out.
- Sweep: recomputes revenue from the campaigns ledger and raises the delivered and clicked figures to what the messaging service reports.
Recipients
| Operation | Scope | What it does |
|---|---|---|
GET /v1/mailings/recipients | mailings.recipients.list | Lists the recipients of mailings. |
GET /v1/mailings/recipients/{id} | mailings.recipients.get | Reads one recipient row. |
- List filters:
mailing_idfor one mailing,outcomefor one outcome, andid,contact_id,email,reason,marketandmessage_id. Paging islimit,offsetandorder, as on the mailings list. - Recipient rows are written by the send pipeline only. A caller cannot change them.
Sending and health
| Operation | Scope | What it does |
|---|---|---|
POST /v1/mailings/send/run | mailings.send.run | Runs the send pipeline once. It prepares due and unfinished mailings chunk by chunk until the time budget is spent. |
GET /v1/mailings/health | mailings.health.read | Reads the sending health of the last 30 days. |
- Send run: the five-minute schedule, callable by hand. Until the known limit above is lifted, a run cannot hand batches to the messaging service.
- Health: sent, delivered, bounced, complained and unsubscribed counts over the mailings of the last 30 days, with their rates.
alertis set when the complaint rate passes the threshold in the app settings.
Variants, blocks and vocabularies
| Operation | Scope | What it does |
|---|---|---|
GET /v1/mailings/variants | mailings.variants.list | Lists the A/B variants of mailings. Empty in this version. |
GET /v1/mailings/variants/{id} | mailings.variants.get | Reads one variant. |
GET /v1/mailings/blocks | mailings.blocks.read | Reads the product, voucher and footer blocks: the keys each carries in a design and the variables that fill it per recipient. |
GET /v1/mailings/vocabularies | mailings.vocabularies.list | Lists the closed vocabularies the app enforces. |
GET /v1/mailings/vocabularies/{name} | mailings.vocabularies.get | Reads one vocabulary with its values and labels. 404 when there is no such vocabulary. |