API v1.0

SendPigeon Documentation

Everything you need to send transactional emails. SDKs for Node.js, Python, Go, PHP and REST API.

Broadcasts

Send marketing emails to your audience with contact management, templates, and tracking.

Broadcasts require a paid plan. Start a free trial or upgrade to access broadcasts.

Overview

Broadcasts let you send marketing emails to groups of contacts. Unlike transactional emails, broadcasts include automatic unsubscribe handling, CAN-SPAM compliance, and engagement tracking.

ResourceDescription
ContactsYour audience members with email, tags, and custom fields
BroadcastsEmail campaigns sent to contacts matching tags
TemplatesReusable email designs for broadcasts

Managing Contacts

Contacts are your audience members. Each contact has an email, optional custom fields, and tags for segmentation.

cURLbash
# List contacts
curl https://api.sendpigeon.dev/v1/contacts \
-H "Authorization: Bearer sp_live_xxx"
 
# Create a contact
curl -X POST https://api.sendpigeon.dev/v1/contacts \
-H "Authorization: Bearer sp_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"fields": { "firstName": "Jane", "company": "Acme" },
"tags": ["newsletter", "beta-users"]
}'
 
# Batch create (up to 100 at once)
curl -X POST https://api.sendpigeon.dev/v1/contacts/batch \
-H "Authorization: Bearer sp_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"contacts": [
{ "email": "user1@example.com", "tags": ["newsletter"] },
{ "email": "user2@example.com", "tags": ["newsletter"] }
]
}'

CSV Import

Import contacts from a CSV file. Max 1000 rows, 5MB file size.

cURLbash
curl -X POST https://api.sendpigeon.dev/v1/contacts/import \
-H "Authorization: Bearer sp_live_xxx" \
-F "file=@contacts.csv"
 
# CSV format: email,firstName,lastName,tags (pipe-separated)
# email,firstName,lastName,tags
# jane@example.com,Jane,Doe,newsletter|beta
Responsejson
{
"created": 95,
"updated": 3,
"skipped": 2,
"errors": [
{ "row": 15, "error": "Invalid email format" }
]
}

Creating Broadcasts

Create a broadcast with your email content, then send or schedule it.

cURLbash
# Create a draft broadcast
curl -X POST https://api.sendpigeon.dev/v1/broadcasts \
-H "Authorization: Bearer sp_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"name": "January Newsletter",
"subject": "What'"'"'s new in 2025",
"fromName": "Acme Updates",
"fromEmail": "updates@yourdomain.com",
"htmlContent": "<h1>Hello {{firstName}}</h1><p>Big news...</p>",
"tags": ["newsletter"]
}'
Responsejson
{
"id": "bc_abc123",
"name": "January Newsletter",
"subject": "What's new in 2025",
"status": "draft",
"tags": ["newsletter"],
"recipientCount": 0,
"sentCount": 0,
"deliveredCount": 0,
"openedCount": 0,
"clickedCount": 0,
"createdAt": "2025-01-15T10:00:00Z"
}

Sending & Scheduling

Send immediately or schedule for later. Broadcasts go to all contacts matching the specified tags.

cURLbash
# Send immediately
curl -X POST https://api.sendpigeon.dev/v1/broadcasts/bc_abc123/send \
-H "Authorization: Bearer sp_live_xxx"
 
# Schedule for later
curl -X POST https://api.sendpigeon.dev/v1/broadcasts/bc_abc123/schedule \
-H "Authorization: Bearer sp_live_xxx" \
-H "Content-Type: application/json" \
-d '{ "scheduledAt": "2025-01-20T09:00:00Z" }'
 
# Cancel a scheduled broadcast
curl -X POST https://api.sendpigeon.dev/v1/broadcasts/bc_abc123/cancel \
-H "Authorization: Bearer sp_live_xxx"

Test Emails

Send a test email to preview your broadcast before sending.

cURLbash
curl -X POST https://api.sendpigeon.dev/v1/broadcasts/bc_abc123/test \
-H "Authorization: Bearer sp_live_xxx" \
-H "Content-Type: application/json" \
-d '{ "to": "your-email@example.com" }'

Personalization

Use {{field}} placeholders in your content. They're replaced with each contact's data.

Template Variablesjson
{
"htmlContent": "<p>Hi {{firstName}},</p><p>Your company {{company}} is...</p>",
"subject": "{{firstName}}, check this out"
}
VariableSource
{{email}}Contact's email
{{fieldName}}Any field from contact's fields object

Unsubscribe Handling

All broadcast emails include List-Unsubscribe headers for one-click unsubscribe (RFC 8058). An unsubscribe link is automatically added if not present in your content.

cURLbash
# Unsubscribe a contact via API
curl -X POST https://api.sendpigeon.dev/v1/contacts/ct_abc123/unsubscribe \
-H "Authorization: Bearer sp_live_xxx"
 
# Resubscribe a contact
curl -X POST https://api.sendpigeon.dev/v1/contacts/ct_abc123/resubscribe \
-H "Authorization: Bearer sp_live_xxx"

Analytics

Track opens, clicks, and delivery status for each broadcast.

cURLbash
curl https://api.sendpigeon.dev/v1/broadcasts/bc_abc123/analytics \
-H "Authorization: Bearer sp_live_xxx"
Responsejson
{
"opensOverTime": [
{ "hour": "2025-01-15T10:00:00Z", "opens": 45 },
{ "hour": "2025-01-15T11:00:00Z", "opens": 128 }
],
"linkPerformance": [
{ "url": "https://example.com/pricing", "clicks": 52, "uniqueClicks": 48 }
]
}

SDK Usage

TypeScripttypescript
import { SendPigeon } from "sendpigeon";
 
const pigeon = new SendPigeon("sp_live_xxx");
 
// Create a contact
const contact = await pigeon.contacts.create({
email: "user@example.com",
fields: { firstName: "Jane" },
tags: ["newsletter"]
});
 
// Create and send a broadcast
const broadcast = await pigeon.broadcasts.create({
name: "Welcome Email",
subject: "Welcome, {{firstName}}!",
htmlContent: "<h1>Hello {{firstName}}</h1>",
fromEmail: "hello@yourdomain.com",
tags: ["newsletter"]
});
 
await pigeon.broadcasts.send(broadcast.id);

Compliance: Broadcasts include CAN-SPAM compliant unsubscribe links and List-Unsubscribe headers. You must set a physical address in your organization settings.