CADENCES

Multi-step outreach your agent runs end-to-end

Define a sequence once — email, LinkedIn connect, follow-up message, conditional branches. Enroll a lead with one API call. MyAgentMail handles the schedule, deliverability, and reply detection — your agent supplies the content per step (with full business context) and reads the outcome to decide what comes next.

Included with every Email and LinkedIn plan. No extra add-on.

The problem cadences solve

Most agent outreach falls apart on day two. The first message is easy — your agent drafts something thoughtful and ships it. Then what? You need follow-ups. You need them to fire only if the prospect didn't reply. You need them to switch channels (email → LinkedIn DM) when the first one goes quiet. You need them to stop the moment a reply comes back, so a human takes over.

Wiring that yourself means cron jobs, a state machine, retry logic, reply detection glued to your inbox webhook, and a way to pause everything when someone says "unsubscribe." It's the kind of plumbing that consumes 80% of a "build an AI SDR" project before the agent has done anything interesting.

Cadences are that plumbing, factored out into the API. You define the steps. We run them.

Three building blocks

Steps, conditions, enrollments. That's the whole model.

1. Steps

What runs

  • linkedin_connect — send a connection request
  • linkedin_message — DM (often gated on accept)
  • email — send a personalized email
  • wait — pause for N hours or days

Each step uses a static template with merge fields (set once at create time) or asks your app for content per-lead via cadence.step.draft.requested webhook — your agent brings the message, MyAgentMail brings the rails. Defined via PUT /v1/cadences/:id/steps.

2. Conditions

When it runs

  • after_accept — only after a LinkedIn invite is accepted
  • no_reply_to_prev — skip if they replied to the previous step
  • never_replied — skip if they replied at any prior step

Conditions gate a step against the lead's history. The runner evaluates them at each tick — no replied-but-still-followed-up mistakes.

3. Enrollments

Who's in it

  • active — runner advances through steps
  • replied / accepted — auto-stops, surfaces to agent
  • bounced / unenrolled / completed — terminal states

Enroll a lead with one POST. Each enrollment carries the prospect's email + LinkedIn URN + arbitrary metadata your agent can read on every reply event.

One worked example

Connect on LinkedIn → wait 2 days → DM if accepted → wait 5 days → email fallback if still silent. Total: ~30 lines.

import { MyAgentMail } from "myagentmail";
const mam = new MyAgentMail({ apiKey: process.env.MAM_KEY! });

// 1. Create the cadence shell
const cadence = await mam.cadences.create({
  name: "Founder outreach — Series A AI",
  inboxId: "ibx_...",        // which inbox sends email steps
  sessionId: "lks_...",      // which LinkedIn session runs LI steps
});

// 2. Define the sequence — your app drafts each step at fire-time
//    via cadence.step.draft.requested webhook. MAM never writes copy.
await mam.cadences.replaceSteps(cadence.id, [
  { kind: "linkedin_connect", drafting: "webhook",
    promptHint: "Warm, 1-sentence note referencing their recent post." },
  { kind: "wait", waitHours: 48 },
  { kind: "linkedin_message", condition: "after_accept", drafting: "webhook",
    promptHint: "Ask if they're open to a 15-min chat about {{topic}}." },
  { kind: "wait", waitHours: 120 },
  { kind: "email", condition: "never_replied", drafting: "webhook",
    promptHint: "Short fallback. Reference the LI connect. Offer value, not a meeting." },
]);

// 3. Enroll a lead
await mam.cadences.enroll(cadence.id, {
  email: "[email protected]",
  linkedinUrn: "urn:li:person:abc123",
  metadata: { topic: "agent-driven outreach", firstName: "Alice" },
});

// 4. Listen for events (webhook or polling)
// cadence.enrollment.replied → your agent jumps in, takes over the thread
// cadence.enrollment.accepted → connection landed, DM step queued
// cadence.enrollment.completed → ran all steps without a reply

The runner ticks every few minutes. Replies coming back to either channel (email or LinkedIn DM) auto-transition the enrollment to replied and stop further steps for that lead. You don't have to detect replies yourself.

What the runner handles for you

The stuff you'd otherwise have to build and maintain forever.

Per-prospect content from your agent

Each step fires a synchronous webhook to your app at send time with the enrollment's metadata + thread context. Your agent drafts the message with full business context — MyAgentMail never sees your prompts. Same cadence, uniquely written for every lead, no mail-merge fingerprint.

Conditional gating

after_accept, no_reply_to_prev, never_replied — evaluated against the lead's full history on every tick. No follow-ups to people who already replied.

Reply detection

Replies on either channel auto-pause the cadence for that lead. message.received and LinkedIn DM webhooks both feed into the enrollment state machine.

Smart scheduling

wait steps respect timezone, send-window preferences, weekends, and per-account warmup limits. The runner ticks every few minutes — no cron to operate.

Channel handoff

A cadence can move a prospect from LinkedIn → email mid-sequence. Same enrollment, same identity, threading preserved.

Safe stop

Unsubscribe footer in emails auto-unenrolls. Manual unenroll via API. Suspended tenants auto-pause every active enrollment instantly.

Reselling to your own customers? Cadences are workspace-scoped at create time — pinned to one inbox and one LinkedIn session that belong to the same workspace. Every tier gives you one isolated workspace per connected LinkedIn account (Solo 2, Team 15, Agency 60), so each of your customers gets their own isolated cadences, sessions, and signals. See LinkedIn pricing for tier details.

API surface

Nine endpoints. Same shape across SDK, REST, and MCP.

Method · pathWhat it does
POST /v1/cadencesCreate a cadence shell
GET /v1/cadencesList your cadences
GET /v1/cadences/:idFetch one with its steps
PATCH /v1/cadences/:idRename, pause, swap inbox/session
DELETE /v1/cadences/:idRemove (also stops active enrollments)
PUT /v1/cadences/:id/stepsReplace the full step list atomically
POST /v1/cadences/:id/enrollmentsEnroll a lead
GET /v1/cadences/:id/enrollmentsList enrollments, filter by state
POST /v1/cadences/:id/runForce a tick now (testing)

Full schemas + try-it pane: /docs (Cadences group). Markdown for LLMs: /docs-md/cadence-create et al.

Agent-callable, too

The MCP server exposes cadence_create, cadence_replace_steps, cadence_enroll_lead, cadence_list_enrollments, cadence_run_now as native MCP tools. Drop into Claude Desktop, Cursor, Windsurf, Cline — your agent can define and run a cadence without writing any of the wiring.

npx -y myagentmail-mcp install

Run your first cadence in 5 minutes.

Included with any Email or LinkedIn plan. 7-day free trial — card required, cancel anytime before day 7.