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.
| Resource | Description |
|---|---|
| Contacts | Your audience members with email, tags, and custom fields |
| Broadcasts | Email campaigns sent to contacts matching tags |
| Templates | Reusable email designs for broadcasts |
Managing Contacts
Contacts are your audience members. Each contact has an email, optional custom fields, and tags for segmentation.
# List contactscurl https://api.sendpigeon.dev/v1/contacts \ -H "Authorization: Bearer sp_live_xxx" # Create a contactcurl -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.
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{ "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.
# Create a draft broadcastcurl -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"] }'{ "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.
# Send immediatelycurl -X POST https://api.sendpigeon.dev/v1/broadcasts/bc_abc123/send \ -H "Authorization: Bearer sp_live_xxx" # Schedule for latercurl -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 broadcastcurl -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.
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.
{ "htmlContent": "<p>Hi {{firstName}},</p><p>Your company {{company}} is...</p>", "subject": "{{firstName}}, check this out"}| Variable | Source |
|---|---|
| {{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.
# Unsubscribe a contact via APIcurl -X POST https://api.sendpigeon.dev/v1/contacts/ct_abc123/unsubscribe \ -H "Authorization: Bearer sp_live_xxx" # Resubscribe a contactcurl -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.
curl https://api.sendpigeon.dev/v1/broadcasts/bc_abc123/analytics \ -H "Authorization: Bearer sp_live_xxx"{ "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
import { SendPigeon } from "sendpigeon"; const pigeon = new SendPigeon("sp_live_xxx"); // Create a contactconst contact = await pigeon.contacts.create({ email: "user@example.com", fields: { firstName: "Jane" }, tags: ["newsletter"]}); // Create and send a broadcastconst 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.