Drip Email API: Build Automated Email Sequences in Code
How to build drip campaigns and email sequences programmatically with an API. Define multi-step flows, triggers, and branching logic in code — not a drag-and-drop editor.
A drip email API lets you create and manage automated email sequences programmatically — define steps, set triggers, manage enrollments, and track analytics via API calls or SDKs instead of a visual editor.
If you're building a SaaS product, this means sequences that are version-controlled, testable, and deployed like the rest of your code.
What it is: An API for building multi-step automated email sequences in code.
Why developers need it: Version control, testing, CI/CD, programmatic enrollment, conditional branching — things visual editors can't do well.
Best option: SendPigeon — full sequences API with 5 step types, event-based triggers, and SDKs for Node.js, Python, Go, PHP.
Why Build Drip Campaigns in Code?
| Visual editor | API-first |
|---|---|
| Click to configure | Define in code |
| Can't version control | Git-tracked |
| Manual testing | Automated tests |
| One-off changes | CI/CD deployable |
| Limited logic | Full branching + webhooks |
| Hard to replicate across environments | Same code in staging + production |
If your app already has event tracking, user segmentation, and deployment pipelines — your email sequences should plug into the same workflow.
Anatomy of a Drip Sequence
Trigger (event, tag, signup, API call)
↓
Step 1: Send welcome email
↓
Step 2: Wait 2 days
↓
Step 3: Branch — has the user activated?
├─ Yes → Send tips email
└─ No → Send nudge email
↓
Step 4: Wait 3 days
↓
Step 5: Send feature highlight
↓
Done (enrollment complete)
Each step is an object with a type and config. The sequence engine handles scheduling, retries, and state management.
Building a Sequence with the API
1. Create the Sequence
import { SendPigeon } from "sendpigeon";
const pigeon = new SendPigeon("sp_live_xxx");
const sequence = await pigeon.sequences.create({
name: "Onboarding",
description: "7-day new user onboarding flow",
triggerType: "CONTACT_CREATED",
});
console.log(sequence.id); // seq_abc123
2. Add Steps
// Step 1: Welcome email (sent immediately on enrollment)
const step1 = await pigeon.sequences.steps.create(sequence.id, {
type: "SEND_EMAIL",
config: {
templateId: "tmpl_welcome",
subject: "Welcome to {{appName}}!",
fromName: "Alice from YourApp",
},
});
// Step 2: Wait 2 days
const step2 = await pigeon.sequences.steps.create(sequence.id, {
type: "WAIT",
config: { type: "delay", duration: 172800 }, // 2 days in seconds
});
// Step 3: Branch on activation status
const step3 = await pigeon.sequences.steps.create(sequence.id, {
type: "BRANCH",
config: {
condition: { type: "has_tag", tag: "activated" },
},
});
// Step 4a: Tips email (true branch — user activated)
const step4a = await pigeon.sequences.steps.create(sequence.id, {
type: "SEND_EMAIL",
config: {
templateId: "tmpl_tips",
subject: "3 things you can do with {{appName}}",
},
});
// Step 4b: Nudge email (false branch — user hasn't activated)
const step4b = await pigeon.sequences.steps.create(sequence.id, {
type: "SEND_EMAIL",
config: {
templateId: "tmpl_nudge",
subject: "Need help getting started?",
},
});
3. Wire the Flow
// Connect the branch to its true/false paths
await pigeon.sequences.steps.update(sequence.id, step3.id, {
branchTrueStepId: step4a.id,
branchFalseStepId: step4b.id,
});
// Set the step order
await pigeon.sequences.steps.reorder(sequence.id, [
{ stepId: step1.id, position: 0, nextStepId: step2.id },
{ stepId: step2.id, position: 1, nextStepId: step3.id },
{ stepId: step3.id, position: 2 },
{ stepId: step4a.id, position: 3 },
{ stepId: step4b.id, position: 4 },
]);
4. Activate
await pigeon.sequences.activate(sequence.id);
New contacts matching the trigger are automatically enrolled.
Step Types
SEND_EMAIL
Sends a template to the enrolled contact.
{
type: "SEND_EMAIL",
config: {
templateId: "tmpl_xxx",
subject: "Optional override",
fromEmail: "hello@yourdomain.com",
fromName: "Your App",
replyTo: "support@yourdomain.com",
}
}
Templates support personalization: {{firstName}}, {{email}}, {{contact.customField}}, and trigger data like {{event.plan}}.
WAIT
Pauses the enrollment before the next step.
// Wait a fixed duration
{ type: "WAIT", config: { type: "delay", duration: 86400 } } // 1 day
// Wait until a specific time of day (UTC)
{ type: "WAIT", config: { type: "time_of_day", hour: 9, minute: 0 } }
// Wait for a condition (with timeout)
{ type: "WAIT", config: { type: "condition", condition: { type: "has_tag", tag: "verified" }, timeout: 604800 } } // 7 days
BRANCH
Splits the flow based on a condition. Contacts go to branchTrueStepId or branchFalseStepId.
{
type: "BRANCH",
config: {
condition: { type: "has_tag", tag: "premium" }
}
}
UPDATE_CONTACT
Modifies the contact mid-sequence. Executes instantly (no delay).
{
type: "UPDATE_CONTACT",
config: {
actions: [
{ type: "add_tag", tag: "onboarded" },
{ type: "set_field", field: "onboardingStage", value: "complete" },
]
}
}
WEBHOOK
Calls an external service. Use it to sync with your CRM, trigger Slack notifications, or update external systems.
{
type: "WEBHOOK",
config: {
url: "https://yourapp.com/api/sequence-hook",
method: "POST",
headers: { "Authorization": "Bearer xxx" },
body: { action: "user_onboarded" },
retries: 3,
failureAction: "continue", // or "exit"
}
}
Triggers
| Trigger | When it fires | Use case |
|---|---|---|
CONTACT_CREATED | New contact added | Onboarding |
TAG_ADDED | Tag applied to contact | Upgrade flow, activation |
EVENT | Custom event sent via API | Any app event |
API_CALL | Manual enrollment via /enroll | Batch operations, migrations |
DATE_PROPERTY | Contact reaches a date field | Trial expiry, renewal reminders |
Event-Based Triggers
The most flexible approach. Fire events from your app, and matching sequences auto-enroll:
// In your app: user upgrades to Pro
await pigeon.events.send({
email: "user@example.com",
name: "plan_upgraded",
properties: { plan: "pro", previousPlan: "free" },
});
// Any sequence with triggerType: "EVENT" and eventName: "plan_upgraded"
// will auto-enroll this contact
Enrollment Management
Manual Enrollment
await pigeon.sequences.enroll(sequence.id, {
contacts: [
{ email: "user1@example.com" },
{ email: "user2@example.com" },
{ contactId: "ct_existing123" },
],
});
Pause / Resume / Exit
// Pause an enrollment (e.g., user opened a support ticket)
await pigeon.sequences.enrollments.pause(sequenceId, enrollmentId);
// Resume later
await pigeon.sequences.enrollments.resume(sequenceId, enrollmentId);
// Exit immediately (e.g., user churned)
await pigeon.sequences.enrollments.exit(sequenceId, enrollmentId);
List Active Enrollments
const { enrollments } = await pigeon.sequences.enrollments.list(sequenceId, {
status: "ACTIVE",
});
for (const enrollment of enrollments) {
console.log(`${enrollment.contactEmail} — step ${enrollment.currentStepId}`);
}
Analytics
const analytics = await pigeon.sequences.analytics(sequenceId);
console.log(`Enrolled: ${analytics.totalEnrolled}`);
console.log(`Active: ${analytics.activeEnrolled}`);
console.log(`Completed: ${analytics.completedCount}`);
console.log(`Exited: ${analytics.exitedCount}`);
// Per-step analytics
const stepStats = await pigeon.sequences.steps.analytics(sequenceId, stepId);
console.log(`Entered: ${stepStats.enteredCount}`);
console.log(`Completed: ${stepStats.completedCount}`);
Why Not Use Customer.io or Loops?
| SendPigeon | Customer.io | Loops | |
|---|---|---|---|
| Built for | Developers | Growth teams | Marketers |
| Sequence management | API + SDK + dashboard | Dashboard + API | Dashboard only |
| Also sends transactional | Yes | Yes | Limited |
| Inbound parsing | Yes | No | No |
| Pricing | $10/mo (Starter) | $100/mo+ | $49/mo+ |
| SDK languages | Node, Python, Go, PHP | Node, Ruby, Python | Node |
| Self-serve | Yes | Yes | Yes |
Customer.io is feature-rich and built for growth/marketing teams. Loops is focused on a visual-first experience with limited API access. SendPigeon is API-first — sequences are a core developer feature, not an add-on.
Pricing
Email sequences are included in all SendPigeon paid plans. Starter ($10/mo) includes 3 sequences with 500 active enrollments. Growth ($15/mo) includes 10 sequences with 5,000 enrollments. Pro ($39/mo) includes 50 sequences with 50,000 enrollments. For a full comparison with Customer.io and Loops pricing, see SendPigeon vs Loops.
Next Steps
- Build an onboarding email sequence — step-by-step tutorial
- Sequences documentation — full API reference
- SendPigeon vs Loops — detailed comparison
- SendPigeon vs Loops — comparison with Loops
- Inbound email parsing — receive emails via webhooks