agentlyleads docs
Emails API

Drip plans — /api/v1/drip-plans

A rep writes fifty individually-worded drafts and then has to send them. Sending them all at once is worse than not sending them: a mailbox that normally emits five a day suddenly emitting fifty in ten minutes is a spam signal in its own right, whatever the emails say.

A drip plan takes a set of drafts and spaces them out — one at a time, with a random gap between each, inside a sending window, capped per mailbox per day, and pulled from the queue if that contact replies first.

Nothing is sent by these endpoints

Creating a plan stamps a send time on each draft and returns the schedule. The every-minute cron is what releases them. You can see the whole queue, and the finish date, before a single email moves.

Create a plan

POST /api/v1/drip-plans HTTP/1.1
Host: agentlyleads.com
Authorization: Bearer alk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json

{
  "name": "Champion closeout round",
  "emailIds": ["cmtsv6ts404hzii01dnmu4k5t", "cmtsv6ts404hzii01dnmu4k5u"],
  "startAt": "2026-09-16T13:00:00.000Z",
  "stopOnReply": true,
  "pacing": { "minGapMinutes": 12, "maxGapMinutes": 35, "dailyCapPerMailbox": 25 }
}

Requires the write:emails scope (or *).

FieldDescription
nameWhat this batch is, for your own reference
emailIdsIds of emails currently in DRAFT, in the order they should go out (1–500)
startAtWhen to begin. Defaults to now; a time outside the window rolls to its next open
stopOnReplyPull a queued message if that contact replies first. Default true
pacingAny of the fields below; anything omitted keeps its default

Pacing

FieldDefaultMeaning
minGapMinutes / maxGapMinutes12 / 35The gap between two sends from the same mailbox, drawn at random per send
dailyCapPerMailbox25Sends allowed from one mailbox on one calendar day
businessHoursOnlytrueClamp every send into the window below
timezoneAmerica/TorontoIANA zone the window and the daily cap's calendar day are read in
windowStartHour / windowEndHour9 / 17The window, in that zone. windowEndHour is exclusive
daysOfWeek[1,2,3,4,5]Allowed weekdays, 0 = Sunday

Pacing is applied per mailbox, not per plan. Two From addresses are two connected mailboxes with two reputations and two daily counters, so a 52-draft batch split across both drains in about half the wall-clock time.

Every id must be a DRAFT in your workspace. A batch containing anything else — already sent, already scheduled, or belonging to another workspace — is refused whole rather than silently shortened, so the schedule you get back is always the real one.

201 returns the plan and the computed time for every message:

{
  "dripPlan": { "id": "cmq2drip0alk34567890", "name": "Champion closeout round", "status": "ACTIVE", "...": "..." },
  "schedule": [
    { "emailId": "cmtsv6ts404hzii01dnmu4k5t", "scheduledAt": "2026-09-16T13:00:00.000Z", "toEmail": "buyer@example.com", "subject": "..." },
    { "emailId": "cmtsv6ts404hzii01dnmu4k5u", "scheduledAt": "2026-09-16T13:21:00.000Z", "toEmail": "other@example.com", "subject": "..." }
  ]
}

Check a plan

GET /api/v1/drip-plans/cmq2drip0alk34567890

Requires read:emails. Returns the plan with counts (total, scheduled, sent, skipped, failed) and every message in send order — still-queued mail first, by time.

A message that was pulled from the queue is back in DRAFT with a skipReason:

skipReasonWhat happened
REPLIEDThe contact answered before their turn, so the batch stopped for them
SUPPRESSEDThey unsubscribed, bounced, or are marked do-not-contact
CANCELEDThe plan was cancelled while this one was still queued

GET /api/v1/drip-plans lists the workspace's plans, newest first, with optional status and limit.

Pause, resume, cancel

POST   /api/v1/drip-plans/cmq2drip0alk34567890/pause
POST   /api/v1/drip-plans/cmq2drip0alk34567890/resume
DELETE /api/v1/drip-plans/cmq2drip0alk34567890

All three require write:emails and return { "dripPlan": { ... } }.

Pause stops sending immediately; queued mail keeps its place. Resume re-spaces whatever is left from now using the plan's own pacing — a plan paused across a day does not fire its backlog the moment it comes back, which would be exactly the burst the feature exists to prevent.

Cancel returns every still-queued email to DRAFT, stamped CANCELED. Nothing is deleted: you wrote those words, and they are still there to re-schedule or send by hand. Mail already sent is untouched — nothing can unsend it, and an API that implied otherwise would be lying.

What a plan defers rather than fails

A paced batch runs for days, so some failures are "not yet" rather than "never". When the workspace's sending is paused for reputation, when it hits its rolling 24-hour cap, or when the mailbox runs out of its own daily slots, the message stays SCHEDULED and moves to the next open slot in the window. Only an actual delivery error — a rejecting server, a broken mailbox — marks a message FAILED.

StatusMeaning
400Invalid body, an id that is not a DRAFT, or an id from another workspace
401Missing, invalid, or expired API key
403Key lacks read:emails / write:emails
404No such plan here — or, for pause/resume/cancel, it is not in a state that allows it

On this page