Sending a campaign (end to end)
The full path from nothing to a live, sending campaign. Each step is one operation through the Tool named in its row below — follow the link for that operation's fields.
Before you start: a campaign can only send from a connected, warmed-up sender. If the account has none, one can be created via sender/post — SMTP/IMAP credentials the user gathers on their provider's site with your guidance. Work through onboarding first.
If more than one sender is connected, ask the user which sender(s) the campaign should send from before creating it — never pick one silently.
Steps
| # | Goal | Tool | Operation |
|---|---|---|---|
| 1 | Confirm you have a real sender to send from | read |
sender/get |
| 2 | Create the campaign — set fromEmails to that sender's address and campaign-level subject + body — collect the user's actual content first (writing-emails); patch before starting if it changes. This alone is a complete, sendable first email (start validates it even when followups carry their own) |
create |
campaign/post |
| 3 | Add a sequence to hold any automated follow-up steps — a sequence itself has no subject/body, just conditions (opened/replied/etc.) for when its followups fire | create |
campaign/post_sequences_by_id |
| 4 | (optional) Add follow-up email(s) to that sequence (subject + body; personalization variables come from a closed list — personalization-variables) — only needed for touches after the first email; skip this entirely for a one-email send | create |
sequence/post_followups_by_id |
| 5 | Add your contacts and enrol them into the campaign — enrolling into a campaign that is already Running starts sending to those prospects immediately | create |
prospect/post_bulk with campaignId |
| 6 | Start sending (validates the personalization variables, then paces the sends) — needs a fresh, send-specific go-ahead from the user (what will be sent, to whom) right before this call, not a general earlier "yes": pass confirm_send: true |
act |
campaign/start_by_id |
| 7 | Confirm it's sending | read |
campaign/stats_by_id |
Step 3 is not optional if you want followups: despite what the underlying API schema may suggest, no sequence exists until you call it —
campaign/get_sequences_by_idreturns an empty list immediately aftercampaign/post.
The two things that silently block a send
-
A real sender.
campaign/postdefaultsfromEmailsto the account's login email, which is usually not a connected sender — the campaign then starts but never sends. Always setfromEmailsto an address returned by sender/get. -
Enrolment is a separate step from creating contacts. Creating a prospect (prospect/post) or moving it to a list does not put it in a campaign. The one operation that enrols is prospect/post_bulk with the
campaignIdargument — it upserts the contacts and adds them to the campaign's first sequence in one call. It merges onto existing prospects (omitted fields are preserved, not cleared), so enrolling contacts who already exist in the CRM this way is safe.
While testing
Send only to an address you control (e.g. your own inbox) — never enrol real prospects into a throwaway test campaign.
Why isn't it sending? (checklist)
The quick list below covers the mistakes people make while building a campaign. If the campaign is already
RunningandsentCountis not moving, work through why-isnt-it-sending instead — it starts from the prospects'sendingStatus, which names the blocker directly, and covers schedule windows, limits and ESP matching. First check there: sending is paced, sosentCount: 0for the first minutes after starting is normal, not a fault.
statusisPaused/Draft→ it only sends whileRunning(campaign/start_by_id — get a fresh, specific yes for this send before starting; an earlier general instruction to fix or run things isn't consent to send). A go-ahead given earlier in the conversation (before the campaign existed or was reviewed) does not count — re-confirm at start time, every time.- Sender problems: not connected, or campaign
dailyLimitexceeds the sender's own limit (sender/get). - Nobody enrolled, or prospects unvalidated (prospect/get with
includeCampaignIds.campaignIds). - Prospects missing a value a variable needs: with
deactivateIfMissingPlaceholder: trueeach one is deactivated rather than mailed (sendingStatus: MissingPlaceholder). Give the variable adefault:fallback, or fill the field — personalization-variables. - For a copied campaign, check the source campaign's stats: copies inherit prospect lists, including ones with heavy bounce history.
- A followup has
useOriginalSubject: truebut the campaign's ownsubjectis empty → start still fails validation (it needs a non-empty effective subject regardless ofuseOriginalSubject) — give the campaign asubject, or the followup its own. To inherit the campaign's subject, omit the followup'ssubjectfield entirely — an explicitsubject: ""defeats inheritance and fails the same way.