Launch and cancel
Both need the write:campaigns scope.
POST /api/v1/campaigns/{id}/launch
Launches a DRAFT campaign now, or at scheduledAt. A SCHEDULED campaign can be launched again to change its time or launch it now.
POST /api/v1/campaigns/cmq2camp0alk34567890/launch HTTP/1.1
Host: agentlyleads.com
Authorization: Bearer alk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json
{ "scheduledAt": "2026-10-01T14:00:00Z" }Send no body, or {}, to launch now.
Launching does not send email. It queues one recipient per contact in the audience that has an email address and is not suppressed. The send tick then writes one draft email per recipient, and a person approves those in the app (the Emails page or the campaign view) before anything leaves. Recipients are recorded once, so launching twice never queues anyone twice.
Before launching, the same checks as the app run:
| Check | Response |
|---|---|
The campaign is not DRAFT or SCHEDULED | 409 |
| Sending is paused for the workspace (reputation protection) | 409 with the reason |
| Nobody in the audience has an email address | 400 |
| No verified sending domain, and the audience is bigger than what is left of today's sending limit | 400 telling you to verify a domain or schedule across days |
Response (200)
{
"campaign": { "id": "cmq2camp0alk34567890", "status": "SCHEDULED", "scheduledAt": "2026-10-01T14:00:00.000Z", "recipientCount": 118, "...": "..." },
"queuedRecipients": 118
}POST /api/v1/campaigns/{id}/cancel
Stops a SCHEDULED or SENDING campaign (or shelves a DRAFT). Nothing further is queued. Drafts already written for recipients stay where they are, so you can still review or delete them in the app. A SENT, CANCELED or OUTREACH campaign returns 409.
{ "campaign": { "id": "cmq2camp0alk34567890", "status": "CANCELED", "...": "..." } }