SendPigeon API Documentation
Everything you need to send transactional emails. Simple REST API and detailed guides.
Quick Start
Send your first email in under a minute.
Create an account and grab your API key from the dashboard.
curl -X POST https://api.sendpigeon.dev/v1/emails \ -H "Authorization: Bearer sp_live_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "from": "hello@yourdomain.com", "to": "user@example.com", "subject": "Welcome!", "html": "<h1>Hello World</h1>" }'{ "id": "em_abc123def456", "status": "sent"}Authentication
Secure your API requests with Bearer token authentication.
All API requests require authentication via a Bearer token in the Authorization header. Get your API key from the dashboard.
curl -X POST https://api.sendpigeon.dev/v1/emails \ -H "Authorization: Bearer sp_live_your_api_key" \ -H "Content-Type: application/json" \ -d '{"from": "...", "to": "...", "subject": "..."}'sp_live_ — use in production. Emails are delivered to real recipients.sp_test_ — use in development. Emails are logged but not sent.Send Email
POST /v1/emails — Send a transactional email.
Request Body
| Parameter | Type | Description |
|---|---|---|
| from* | string | Sender email address. Domain must be verified. |
| to* | string | string[] | Recipient email address(es). |
| subject | string | Email subject. Required unless using templateId. |
| html | string | HTML body content. |
| text | string | Plain text body content. |
| cc | string | string[] | CC recipients. |
| bcc | string | string[] | BCC recipients. |
| replyTo | string | Reply-to address. |
| templateId | string | Template ID to use instead of subject/body. |
| variables | object | Variables to substitute in template. |
Headers
| Header | Description |
|---|---|
| Idempotency-Key | Unique key to prevent duplicate sends. Same key returns cached response. |
Example Request
curl -X POST https://api.sendpigeon.dev/v1/emails \ -H "Authorization: Bearer sp_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "from": "hello@acme.com", "to": "user@example.com", "subject": "Your order shipped!", "html": "<h1>Order #1234</h1>", "replyTo": "support@acme.com" }'Response
{ "id": "em_abc123def456", "status": "sent", "suppressed": []}sent, queued, failed, delivered, bounced, complainedTemplates
Create reusable email templates with variable substitution.
Templates use {{variable}} syntax for dynamic content. Variables are automatically detected when you create or update a template.
Create Template
POST /v1/templatescurl -X POST https://api.sendpigeon.dev/v1/templates \ -H "Authorization: Bearer sp_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "name": "welcome-email", "subject": "Welcome to {{company}}, {{name}}!", "html": "<h1>Hello {{name}}</h1><p>Welcome aboard.</p>" }'{ "id": "tpl_abc123", "name": "welcome-email", "subject": "Welcome to {{company}}, {{name}}!", "variables": ["company", "name"]}Send with Template
curl -X POST https://api.sendpigeon.dev/v1/emails \ -H "Authorization: Bearer sp_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "from": "hello@acme.com", "to": "user@example.com", "templateId": "tpl_abc123", "variables": { "name": "John", "company": "Acme Inc" } }'Template Endpoints
| Method | Endpoint | Description |
|---|---|---|
| GET | /v1/templates | List all templates |
| POST | /v1/templates | Create a template |
| GET | /v1/templates/:id | Get a template |
| PATCH | /v1/templates/:id | Update a template |
| DELETE | /v1/templates/:id | Delete a template |
Error Codes
HTTP status codes and error responses.
| Status | Meaning | Resolution |
|---|---|---|
| 400 | Bad Request | Check request body format and required fields. |
| 401 | Unauthorized | Verify API key is valid and properly formatted. |
| 402 | Quota Exceeded | Upgrade your plan or wait for quota reset. |
| 403 | Domain Not Verified | Add DNS records for your sending domain. |
| 404 | Not Found | Check the resource ID exists. |
| 429 | Rate Limited | Slow down requests. Max 100/minute. |
| 500 | Server Error | Retry with exponential backoff. |
Error Response Format
{ "message": "Domain not verified. Add DNS records first."}Rate Limits
API requests are limited to 100 requests per minute per API key. Rate limit headers are included in every response:
X-RateLimit-Limit: 100X-RateLimit-Remaining: 95X-RateLimit-Reset: 1640995200TypeScript SDK Coming Soon
We're building a TypeScript SDK for Node.js and edge runtimes. In the meantime, use the REST API directly — it's simple and works everywhere.