SendPigeon Documentation
Everything you need to send transactional emails. SDKs for Node.js, Python, Go, PHP and REST API.
Sequences
Automate multi-step email workflows triggered by events, contact creation, or API calls.
Free plan included. Free accounts get 1 sequence and 100 active enrollments. Upgrade to Starter for more sequences, higher enrollment limits, and event-based triggers. Requires SDK v1.12.0+.
Overview
A sequence is a series of steps (emails, waits, branches) executed automatically for each enrolled contact. Contacts enter a sequence when a trigger fires — an event, contact creation, a tag being added, or a direct API call.
| Resource | Description |
|---|---|
| Sequence | The workflow definition — trigger, steps, and settings |
| Step | A single action: send email, wait, branch, update contact, or webhook |
| Enrollment | A contact's progress through a sequence |
Trigger Types
| Trigger | When it fires |
|---|---|
| EVENT | A custom event is sent via events.send |
| CONTACT_CREATED | A new contact is added to your audience |
| TAG_ADDED | A specific tag is added to a contact |
| API_CALL | Manual enrollment via sequences.enroll |
| DATE_PROPERTY | A date field on the contact (e.g. trial expiry, birthday) |
Create a Sequence
const { data: sequence } = await pigeon.sequences.create({ name: "Welcome Drip", triggerType: "API_CALL", reentryAllowed: false,}); // Activate it so enrollments can beginawait pigeon.sequences.activate(sequence.id);Sequences start in DRAFT status. Call activate before enrolling contacts.
Add Steps
// Step 1: send a welcome email immediatelyawait pigeon.sequences.steps.create(sequence.id, { type: "SEND_EMAIL", config: { fromEmail: "hello@yourdomain.com", subject: "Welcome!", templateId: "tpl_abc123", },}); // Step 2: wait 3 daysawait pigeon.sequences.steps.create(sequence.id, { type: "WAIT", config: { delay: 3, unit: "days" },}); // Step 3: send a follow-upawait pigeon.sequences.steps.create(sequence.id, { type: "SEND_EMAIL", config: { fromEmail: "hello@yourdomain.com", subject: "How are you settling in?", templateId: "tpl_def456", },});Enroll Contacts
For API_CALL sequences, enroll contacts directly. For event-based sequences, fire the event instead.
// Enroll by contact IDconst { data } = await pigeon.sequences.enroll(sequence.id, { contactId: "ct_abc123",}); // Or trigger via event (for EVENT trigger type)await pigeon.events.send({ name: "user.signed_up", contactId: "ct_abc123", data: { plan: "starter" },});Manage Enrollments
// List enrollments for a sequenceconst { data } = await pigeon.sequences.enrollments.list(sequence.id); // Pause an enrollmentawait pigeon.sequences.enrollments.pause(sequence.id, enrollmentId); // Resume a paused enrollmentawait pigeon.sequences.enrollments.resume(sequence.id, enrollmentId); // Exit (remove) a contact from a sequenceawait pigeon.sequences.enrollments.exit(sequence.id, enrollmentId);REST API
# Create a sequencecurl -X POST https://api.sendpigeon.dev/v1/sequences \ -H "Authorization: Bearer sk_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "name": "Welcome Drip", "triggerType": "API_CALL", "reentryAllowed": false }' # Activatecurl -X POST https://api.sendpigeon.dev/v1/sequences/seq_abc123/activate \ -H "Authorization: Bearer sk_live_xxx" # Add a stepcurl -X POST https://api.sendpigeon.dev/v1/sequences/seq_abc123/steps \ -H "Authorization: Bearer sk_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "type": "SEND_EMAIL", "config": { "fromEmail": "hello@yourdomain.com", "subject": "Welcome!", "templateId": "tpl_abc123" } }' # Enroll a contactcurl -X POST https://api.sendpigeon.dev/v1/sequences/seq_abc123/enroll \ -H "Authorization: Bearer sk_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "contactId": "ct_abc123" }'Analytics
const { data } = await pigeon.sequences.analytics(sequence.id);// { totalEnrolled, active, completed, exited, openRate, clickRate } // Per-step analyticsconst stepData = await pigeon.sequences.steps.analytics(sequence.id, stepId);// { enteredCount, completedCount, openRate, clickRate }Lifecycle: Sequences move through DRAFT → ACTIVE → PAUSED / ARCHIVED. Only active sequences accept new enrollments. Pausing a sequence halts new step execution but does not exit existing enrollments.