API v1.0

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.

ResourceDescription
SequenceThe workflow definition — trigger, steps, and settings
StepA single action: send email, wait, branch, update contact, or webhook
EnrollmentA contact's progress through a sequence

Trigger Types

TriggerWhen it fires
EVENTA custom event is sent via events.send
CONTACT_CREATEDA new contact is added to your audience
TAG_ADDEDA specific tag is added to a contact
API_CALLManual enrollment via sequences.enroll
DATE_PROPERTYA date field on the contact (e.g. trial expiry, birthday)

Create a Sequence

TypeScripttypescript
const { data: sequence } = await pigeon.sequences.create({
name: "Welcome Drip",
triggerType: "API_CALL",
reentryAllowed: false,
});
 
// Activate it so enrollments can begin
await pigeon.sequences.activate(sequence.id);

Sequences start in DRAFT status. Call activate before enrolling contacts.

Add Steps

TypeScripttypescript
// Step 1: send a welcome email immediately
await pigeon.sequences.steps.create(sequence.id, {
type: "SEND_EMAIL",
config: {
fromEmail: "hello@yourdomain.com",
subject: "Welcome!",
templateId: "tpl_abc123",
},
});
 
// Step 2: wait 3 days
await pigeon.sequences.steps.create(sequence.id, {
type: "WAIT",
config: { delay: 3, unit: "days" },
});
 
// Step 3: send a follow-up
await 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.

TypeScripttypescript
// Enroll by contact ID
const { 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

TypeScripttypescript
// List enrollments for a sequence
const { data } = await pigeon.sequences.enrollments.list(sequence.id);
 
// Pause an enrollment
await pigeon.sequences.enrollments.pause(sequence.id, enrollmentId);
 
// Resume a paused enrollment
await pigeon.sequences.enrollments.resume(sequence.id, enrollmentId);
 
// Exit (remove) a contact from a sequence
await pigeon.sequences.enrollments.exit(sequence.id, enrollmentId);

REST API

cURLbash
# Create a sequence
curl -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
}'
 
# Activate
curl -X POST https://api.sendpigeon.dev/v1/sequences/seq_abc123/activate \
-H "Authorization: Bearer sk_live_xxx"
 
# Add a step
curl -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 contact
curl -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

TypeScripttypescript
const { data } = await pigeon.sequences.analytics(sequence.id);
// { totalEnrolled, active, completed, exited, openRate, clickRate }
 
// Per-step analytics
const stepData = await pigeon.sequences.steps.analytics(sequence.id, stepId);
// { enteredCount, completedCount, openRate, clickRate }

Lifecycle: Sequences move through DRAFTACTIVE PAUSED / ARCHIVED. Only active sequences accept new enrollments. Pausing a sequence halts new step execution but does not exit existing enrollments.