Campaigns
A campaign is a bulk send to a resolved audience. Campaign jobs are routed to leadx-ms-send-manager; one-to-one messages and AI Genie outreach go elsewhere. If you are sending to many people from a template, this is the right surface.
Before you create one
You need three things:
- An audience — at least one selector must be switched on.
- A template — see Templates below.
- A sending app — for
type: "email", an SMTP/provider configuration from Integrations.
Audience selection
Audience is expressed as a set of boolean switches plus the matching data. At least one of the *Bool flags must be true, or creation fails with CampaignSegmentsRequired_400.
| Flag | Pairs with | Meaning |
|---|---|---|
segmentsBool | segments: [id] | Saved segments. |
tagsBool | customAudience.tags | Contacts carrying these tags. |
categoriesBool | customAudience.categories | Contacts in these categories. |
contactsBool | customAudience.contacts | An explicit contact id list. |
customSegmentsBool | customAudience | An inline advanced-filter audience. |
A segment id that doesn't resolve is reported as CampaignSegmentNotFound_400 naming the missing ids — deliberately distinct from an audience that resolves to nobody, which is CampaignAudienceEmpty_400.
Preview before committing
curl -X POST https://api.leadx.in/api/key/protected/campaign/audience-preview \
-H "apikey: $KEY" -H "Content-Type: application/json" \
-d '{ "segmentsBool": true, "segments": ["665a..."] }'
Always do this first. An empty audience refuses campaign creation outright.
Create
curl -X POST https://api.leadx.in/api/key/protected/campaign \
-H "apikey: $KEY" -H "Content-Type: application/json" \
-d '{
"name": "Q3 product announcement",
"type": "email",
"description": "Announcing the analytics tier",
"segmentsBool": true,
"segments": ["665a..."],
"template": "665c...",
"smtp": { "id": "665d..." },
"scheduleType": "scheduled",
"startAt": "2026-09-15T09:00:00.000Z",
"endAt": "2026-09-20T17:00:00.000Z",
"timeWindow": { "start": "09:00", "end": "17:00" },
"daysOfWeek": [1, 2, 3, 4, 5],
"intervalMs": 2000,
"startCampaign": false
}'
| Field | Notes |
|---|---|
name | Required. Must be unique per company (CampaignNameAlreadyExists_400). |
type | Required. email, whatsapp, and the other configured channels. |
template | Template id for the channel. |
smtp | { id } of the sending configuration. Required at start time for email. |
scheduleType / startAt / endAt | When it runs. |
timeWindow / daysOfWeek | Throttle sends to business hours. daysOfWeek is 0–6, Sunday = 0. |
intervalMs | Delay between sends, for provider rate limits. |
triggerWorkflow | Default true — whether sends emit workflow events. |
startCampaign | true starts immediately; false creates it idle. |
:::warning Plan limits still apply here
Campaign creation checks the plan's campaign allowance directly, not through the middleware an API key skips. Exceeding it returns PlanLimitExceeded_403.
:::
Run control
| Method | Endpoint | Purpose |
|---|---|---|
PUT | /campaign/:id/play-pause | Pause or resume. |
PUT | /campaign/:id/continue | Move a failed campaign back to active. |
POST | /campaign/:id/retry-failed | Retry failed recipients. |
POST | /campaign/:id/sync-failed | Re-sync the failed contact list. |
POST | /campaign/:id/assignTag | Tag everyone who failed — handy for a follow-up segment. |
POST | /campaign/test/:type | Send a test message without touching the audience. |
Always send a test first. POST /campaign/test/:type is the only way to see a rendered message before committing to the whole audience.
Monitoring
# Per-recipient outcomes
curl -G https://api.leadx.in/api/key/protected/campaign/665f.../recipients \
-H "apikey: $KEY" \
--data-urlencode 'status=failed' --data-urlencode 'page=1' --data-urlencode 'limit=50'
# Campaign-level log
curl https://api.leadx.in/api/key/protected/campaign/665f.../logs -H "apikey: $KEY"
/recipients is the per-person report from the v2 send engine and is the one to build dashboards on. Note it uses page and limit rather than the usual p and n.
Delivery events per provider live under /logs.
Manual campaigns
| Method | Endpoint |
|---|---|
GET / POST | /campaign/manual |
GET | /campaign/manual/:id |
Manual campaigns are one-off sends assembled outside the scheduled pipeline.
Templates
| Method | Endpoint | Notes |
|---|---|---|
GET / POST / DELETE | /template/email | Email templates. |
GET / PUT | /template/email/:id | |
POST | /template/email/generate-ai | Draft an email template with AI. |
GET / POST / DELETE | /template/whatsapp | WhatsApp templates. |
GET | /template/whatsapp/:id | |
POST | /template/whatsapp/generate-ai | Draft a WhatsApp template with AI. |
POST | /template/whatsapp/status-reconcile | Pull approval status from Meta. |
GET | /template/category/:panel | Available template categories. |
:::note WhatsApp templates need Meta approval
A WhatsApp template must be approved by Meta before a campaign can send it. Create it, then poll status-reconcile until it reports approved. Approved templates cannot be edited — CannotUpdateApprovedTemplate_400.
:::