SendPigeon Documentation
Everything you need to send transactional emails. SDKs for Node.js, Python, Go, PHP and REST API.
Tracking
Track email opens and clicks. Configure organization defaults and per-domain overrides.
Paid plan required. Tracking is available on Starter, Growth, and Pro plans.
Per-Email Tracking
Tracking is opt-in per email. This gives you full control - enable tracking on marketing emails while keeping security emails (password resets, 2FA) tracking-free. Request tracking when sending an email:
curl -X POST https://api.sendpigeon.dev/v1/emails \ -H "Authorization: Bearer sp_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "to": "user@example.com", "from": "hello@yourdomain.com", "subject": "Welcome!", "html": "<p>Hello world</p>", "tracking": { "opens": true, "clicks": true } }'If tracking is disabled at the organization level, tracking options are ignored and a warning is returned in the response.
How It Works
| Type | Mechanism |
|---|---|
| Open tracking | Invisible 1x1 pixel loaded when email is viewed |
| Click tracking | Links rewritten to pass through tracking endpoint |
Organization Settings
Configure organization-wide tracking settings (master toggle, privacy mode, webhook behavior):
# Get organization tracking defaultscurl https://api.sendpigeon.dev/v1/tracking/defaults \ -H "Authorization: Bearer sp_live_xxx" # Update organization tracking defaultscurl -X PATCH https://api.sendpigeon.dev/v1/tracking/defaults \ -H "Authorization: Bearer sp_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "trackingEnabled": true, "privacyMode": false, "webhookOnEveryOpen": false, "webhookOnEveryClick": false }'Webhook behavior: By default, webhooks fire only on the first open/click per email. Enable webhookOnEveryOpen or webhookOnEveryClick to receive a webhook for every event. This can significantly increase webhook volume.
Webhook Events
When tracking is enabled, you'll receive webhook events for opens and clicks:
// email.opened{ "event": "email.opened", "timestamp": "2025-01-15T10:30:00Z", "data": { "emailId": "em_abc123", "toAddress": "user@example.com", "openedAt": "2025-01-15T10:30:00Z" }} // email.clicked{ "event": "email.clicked", "timestamp": "2025-01-15T10:31:00Z", "data": { "emailId": "em_abc123", "toAddress": "user@example.com", "clickedAt": "2025-01-15T10:31:00Z", "linkUrl": "https://example.com/activate", "linkIndex": 0 }}Custom Tracking Domain
By default, tracking links use t.sendpigeon.dev. On Pro, you can use your own subdomain like t.yourdomain.com.
Why it matters: Custom tracking domains improve deliverability because links point to your domain, not a third-party. Email clients trust links that match your sending domain. It also removes SendPigeon branding from your emails.
| Type | Name | Value |
|---|---|---|
| CNAME | t.yourdomain.com | t.sendpigeon.dev |
# Set custom tracking domaincurl -X POST https://api.sendpigeon.dev/v1/domains/{domainId}/tracking/set-domain \ -H "Authorization: Bearer sp_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "trackingDomain": "t.yourdomain.com" }' # Verify CNAME is configuredcurl -X POST https://api.sendpigeon.dev/v1/domains/{domainId}/tracking/verify \ -H "Authorization: Bearer sp_live_xxx"Privacy Mode
Enable privacy mode to track opens/clicks without collecting IP addresses, user agents, or location data. Counts only.
curl -X PUT https://api.sendpigeon.dev/v1/domains/{domainId}/tracking \ -H "Authorization: Bearer sp_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "openTracking": true, "clickTracking": true, "privacyMode": true }'Bot filtering: We filter out known bots, image proxies, and prefetch requests to give you accurate metrics.