MailerAddCampaign¶
POST mailer/campaign
Creates a campaign: one content, one provider profile, and a recipient set described either by explicit ids or by platform filters. The module resolves the recipients, queues the emails in batches and keeps the counters.
A campaign differs from MailerSendBulk in that it is a managed rollout: it has a cursor, can be cancelled and resumed, and its recipients are resolved from the platform at rollout time rather than being pasted into the request.
Recipients¶
The recipient set is resolved at rollout time, not when the campaign is created.
recipientType |
Resolved from | Scope |
|---|---|---|
CUSTOMER |
platform customers with lifecycle_stage > 0 |
deskFilter intersected with the desks of the campaign author |
LEAD |
platform customers with lifecycle_stage = 0 |
same |
MANAGER |
platform managers | filters only |
A lead is not a separate entity on the platform: it is a customer at lifecycle stage 0, so the two audiences never overlap.
Customer email addresses are masked in the platform list command, so the module reads the
address of every recipient separately. That call needs see_customer_contacts on the
campaign author; without it recipients land in skippedCount instead of being emailed.
Access Control¶
Allowed roles: admin, leader. The campaign belongs to the brand of the caller.
Request¶
{
"name": "Summer promo",
"recipientType": "CUSTOMER",
"recipientConfig": {
"filters": {
"deskFilter": "DESK_EU*",
"where": [["country_of_residence", "=", "UA"]]
}
},
"templateId": 4,
"kind": "MARKETING",
"status": "PENDING"
}
{
"command": "MailerAddCampaign",
"extID": "1",
"data": {
"name": "Summer promo",
"recipientType": "CUSTOMER",
"recipientConfig": {
"filters": {
"deskFilter": "DESK_EU*",
"where": [["country_of_residence", "=", "UA"]]
}
},
"templateId": 4,
"kind": "MARKETING",
"status": "PENDING"
}
}
const res = await platform.MailerAddCampaign({
name: "Summer promo",
recipientType: "CUSTOMER",
recipientConfig: {
filters: {
deskFilter: "DESK_EU*",
where: [["country_of_residence", "=", "UA"]]
}
},
templateId: 4,
kind: "MARKETING",
status: "PENDING"
});
Request Data¶
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Campaign name, 1..255 characters |
description |
string | No | Free-form note |
recipientType |
enum | Yes | CUSTOMER, LEAD, or MANAGER |
recipientConfig |
object | Yes | { ids: [...] }, { filters: {...} }, or both. filters are platform filters: deskFilter plus where, orWhere, whereNot, whereIn, whereNotIn, whereBetween, whereNotBetween, orderBy |
templateId |
int | No | Template to render for every recipient |
subject |
string | No | Subject, when the content is passed inline |
html |
string | No | HTML body |
text |
string | No | Plain-text part; generated from the HTML when omitted |
structure |
array | No | Email builder tree |
profileId |
int | No | Explicit provider profile for the whole campaign |
kind |
enum | No | TRANSACTIONAL or MARKETING |
scheduledAt |
string | No | ISO 8601 start time; empty starts the rollout immediately |
status |
enum | No | DRAFT (default) or PENDING to hand it to the scheduler |
Behavior¶
- A campaign created as
DRAFTis not rolled out until it is switched toPENDING— that is the difference between saving a draft and pressing send. - Recipients are resolved through the CRM at rollout time, so a segment that changed between creation and start is honored.
- Estimate the size first with MailerEstimateCampaignRecipients: a filter that matches the whole customer base is easier to catch before the first batch than after it.
- Every queued email carries a dedupe key
campaign:{id}:{recipientId}, so a resumed or restarted rollout cannot email the same recipient twice.
Response Data¶
{
"id": 3,
"brand": "default",
"name": "Summer promo",
"description": null,
"recipientType": "CUSTOMER",
"recipientConfig": { "filters": { "deskFilter": "DESK_EU*", "where": [["country_of_residence", "=", "UA"]] } },
"templateId": 4,
"profileId": null,
"kind": "MARKETING",
"status": "PENDING",
"scheduledAt": null,
"totalRecipients": 0,
"queued": 0,
"failed": 0,
"cursorStage": "IDS",
"cursorOffset": 0,
"createdAt": "2026-08-24 13:20:11"
}
Errors¶
| Code | Error | Description |
|---|---|---|
400 |
VALIDATION_ERROR |
No recipient config, or neither content nor template |
409 |
CAMPAIGN_TOO_LARGE |
The recipient set exceeds the configured campaign limit |
404 |
NOT_FOUND |
Template or profile not found in the brand |