campaign/start_by_id
Tool: act
Start a campaign (transition to Running).
Validates the personalization variables in the campaign's own subject/body and in all followup subjects/bodies, then begins sending to enrolled prospects. First send begins approximately 1–4 minutes after start (observed live). delayMinSeconds controls the minimum delay between consecutive sends after the first, not the initial delay, and it is in seconds (30 means 30 seconds, not 30 minutes).
A nonexistent campaign ID returns 422 "not found or access denied", NOT 404 (upstream quirk).
This starts sending real email — requires
confirm_send: truein arguments (the call is rejected withMCP_CONFIRMATION_REQUIREDwithout it). Consent must be fresh and specific to this send: right before calling, tell the user what will be sent and to whom, and get their explicit yes. A general or earlier "go ahead" does NOT satisfy this — "yes, fix it" / "get this running" from earlier in the conversation does not count, and neither does the user merely asking how to send or what's needed. Only setconfirm_send: trueif you have just asked the user to confirm THIS send and they agreed in this exact context. When in doubt, ask first.
Personalization is validated here (422). The variable vocabulary is a closed set — not a derivation from prospect field names, so
custom1is{{CUSTOM_1}}and{{CUSTOM1}}fails: personalization-variables. The error names every offending expression at once, groupedFix Subject:/Fix Body:, so one round trip fixes them all:Wrong placeholder: {{X}}means no such name exists in any casing, whilePlaceholder has to match correct case. Change {{x}} to {{X}}.names the exact form to use. Nothing was sent — repair the copy with campaign/patch_by_id or followup/patch_by_id and start again. Caveat: an expression containing a|(adefault:fallback, say) is not checked at all, so spell the name correctly before adding a filter.
Preflight checklist — start only sends if all of these hold: (1)
fromEmailsis a connected sender (sender/get); (2) at least one prospect is enrolled (prospect/post_bulk withcampaignId); (3) campaign-levelsubject+bodyare set (validated at start even when followups carry their own). Missing (1) or (2), the campaign transitions to Running but never sends; missing (3) is a 422. Upstream checks these one at a time and fails fast on whichever it hits first (often just namingfromEmails) — expect to work through this checklist in order rather than seeing every gap in one response. Full flow: sending-a-campaign.
Arguments
| name | type | req | notes |
|---|---|---|---|
| id | integer | ✓ | Campaign ID — the object's campaignId |
| confirm_send | boolean | ✓ | Required to actually start sending — set true only after your user gave a fresh, specific yes to this send (a general earlier go-ahead doesn't count) |
Response
200 — {campaignId: integer, status: string}. Deltas: none. The action response returns lowercase status: "running" while GETs return Title-Case "Running" — normalize before comparing (upstream inconsistency).
Errors: 400, 401, 404, 406, 409, 415, 422, 429, 500 — shared schema: schemas/errors. 422 on an unrecognized personalization variable (see above).
After starting, sending is paced — the first email typically lands within about a minute, but several minutes is normal.
sentCount: 0with every prospect onsendingStatus: NotSetis what a healthy campaign looks like during that wait, so give it a few minutes before concluding anything. If it stays quiet, work through why-isnt-it-sending.
Invoke
Call act with name: "campaign/start_by_id".