Campaigns
The Campaigns API allows you to create, manage, and monitor email campaigns at scale.
Base URL
https://api.unsent.dev/v1/campaignsFeatures
Campaign creation
Create email campaigns with rich content
Scheduling
Schedule campaigns for optimal delivery times
Batch processing
Send to large contact lists efficiently
Campaign control
Pause, resume, and monitor active campaigns
Performance tracking
Real-time delivery and engagement metrics
Personalization
Use contact data for dynamic content
Endpoints
List Campaigns
Retrieve a list of all email campaigns for your team, ordered by creation date (newest first).
Endpoint: GET /v1/campaigns
Response Schema
Each campaign object in the array includes:
| Field | Type | Description |
|---|---|---|
id | string | Unique campaign identifier |
name | string | Internal campaign name |
subject | string | Email subject line |
status | string | null | Campaign status (DRAFT, SCHEDULED, SENDING, PAUSED, COMPLETED) |
created_at | string | ISO 8601 timestamp of campaign creation |
sent | number | Number of emails sent |
delivered | number | Number of emails delivered |
opened | number | Number of unique opens |
clicked | number | Number of unique clicks |
Response Example
[
{
"id": "cmp_abc123",
"name": "Welcome Series - January 2024",
"subject": "Welcome aboard! Let's get started",
"status": "COMPLETED",
"created_at": "2024-01-15T12:00:00.000Z",
"sent": 1250,
"delivered": 1240,
"opened": 890,
"clicked": 320
},
{
"id": "cmp_xyz789",
"name": "Holiday Promotion",
"subject": "Special Holiday Offers Inside ๐",
"status": "SENDING",
"created_at": "2024-01-10T09:30:00.000Z",
"sent": 5420,
"delivered": 5380,
"opened": 2150,
"clicked": 640
}
]Create Campaign
Create a new email campaign. You can save it as a draft, send it immediately, or schedule it for later delivery.
Endpoint: POST /v1/campaigns
[!IMPORTANT] The campaign content MUST include an unsubscribe link placeholder
{{unsent_unsubscribe_url}}. Campaigns without this placeholder will be rejected.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Internal name for the campaign (not visible to recipients) |
from | string | Yes | Sender email address (must be from a verified domain) |
subject | string | Yes | Email subject line |
contactBookId | string | Yes | ID of the contact book to send to |
html | string | No* | HTML content of the email |
content | string | No* | Plain text or markdown content |
previewText | string | No | Preview text shown in email client (recommended for better engagement) |
replyTo | string | string[] | No | Reply-to email address(es) |
cc | string | string[] | No | CC email address(es) |
bcc | string | string[] | No | BCC email address(es) |
sendNow | boolean | No | If true, sends the campaign immediately |
scheduledAt | string | No | Schedule time (ISO 8601 format or natural language) |
batchSize | number | No | Number of emails per batch (1-100,000). Helps control sending rate |
*Either html or content must be provided
Natural Language Scheduling
The scheduledAt field supports both ISO 8601 timestamps and natural language:
- ISO 8601:
"2024-01-20T10:00:00Z" - Natural language:
"tomorrow 10am","next monday 9:30","in 2 hours"
Request Example
{
"name": "Weekly Newsletter - Week 3",
"from": "newsletter@yourdomain.com",
"subject": "This Week's Top Stories",
"previewText": "Discover what happened this week in tech...",
"contactBookId": "cb_123456",
"html": "<html><body><h1>Hello {{firstName}}!</h1><p>Here are this week's highlights...</p><p><a href=\"{{unsent_unsubscribe_url}}\">Unsubscribe</a></p></body></html>",
"replyTo": "support@yourdomain.com",
"batchSize": 1000,
"scheduledAt": "tomorrow 9am"
}Response Schema
| Field | Type | Description |
|---|---|---|
id | string | Unique campaign identifier |
name | string | Campaign name |
from | string | Sender email address |
subject | string | Email subject line |
previewText | string | null | Email preview text |
contactBookId | string | null | Associated contact book ID |
html | string | null | HTML content |
content | string | null | Plain text content |
status | string | Current campaign status |
scheduledAt | string | null | ISO 8601 datetime when campaign is scheduled |
batchSize | number | Number of emails per batch |
batchWindowMinutes | number | Minutes between batches |
total | number | Total emails to send |
sent | number | Number of emails sent |
delivered | number | Number of emails delivered |
opened | number | Number of unique opens |
clicked | number | Number of unique clicks |
unsubscribed | number | Number of unsubscribes |
bounced | number | Total bounces |
hardBounced | number | Number of hard bounces |
complained | number | Number of spam complaints |
replyTo | string[] | Reply-to addresses |
cc | string[] | CC addresses |
bcc | string[] | BCC addresses |
createdAt | string | ISO 8601 timestamp of creation |
updatedAt | string | ISO 8601 timestamp of last update |
Response Example
{
"id": "cmp_new789",
"name": "Weekly Newsletter - Week 3",
"from": "newsletter@yourdomain.com",
"subject": "This Week's Top Stories",
"previewText": "Discover what happened this week in tech...",
"contactBookId": "cb_123456",
"html": "<html><body><h1>Hello {{firstName}}!</h1><p>Here are this week's highlights...</p><p><a href=\"{{unsent_unsubscribe_url}}\">Unsubscribe</a></p></body></html>",
"content": null,
"status": "SCHEDULED",
"scheduledAt": "2024-01-16T09:00:00.000Z",
"batchSize": 1000,
"batchWindowMinutes": 5,
"total": 0,
"sent": 0,
"delivered": 0,
"opened": 0,
"clicked": 0,
"unsubscribed": 0,
"bounced": 0,
"hardBounced": 0,
"complained": 0,
"replyTo": ["support@yourdomain.com"],
"cc": [],
"bcc": [],
"createdAt": "2024-01-15T14:30:00.000Z",
"updatedAt": "2024-01-15T14:30:00.000Z"
}Get Campaign
Retrieve detailed information and statistics for a specific campaign.
Endpoint: GET /v1/campaigns/{campaignId}
Path Parameters
| Parameter | Type | Description |
|---|---|---|
campaignId | string | The campaign ID (e.g., cmp_123) |
Response Schema
Same as the Create Campaign response schema (see above).
Response Example
{
"id": "cmp_abc123",
"name": "Product Launch Campaign",
"from": "launches@yourdomain.com",
"subject": "Introducing Our Latest Product!",
"previewText": "Be the first to experience our revolutionary new feature",
"contactBookId": "cb_456789",
"html": "<html><body>...</body></html>",
"content": null,
"status": "COMPLETED",
"scheduledAt": null,
"batchSize": 500,
"batchWindowMinutes": 5,
"total": 10000,
"sent": 10000,
"delivered": 9850,
"opened": 6200,
"clicked": 2100,
"unsubscribed": 45,
"bounced": 150,
"hardBounced": 80,
"complained": 3,
"replyTo": ["support@yourdomain.com"],
"cc": [],
"bcc": ["archive@yourdomain.com"],
"createdAt": "2024-01-10T08:00:00.000Z",
"updatedAt": "2024-01-10T16:45:00.000Z"
}Schedule Campaign
Schedule or reschedule an existing campaign for future delivery.
Endpoint: POST /v1/campaigns/{campaignId}/schedule
Path Parameters
| Parameter | Type | Description |
|---|---|---|
campaignId | string | The campaign ID (e.g., cmp_123) |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
scheduledAt | string | No | Date/time to send (ISO 8601 or natural language like "tomorrow 10am", "next monday 9:30") |
batchSize | number | No | Max emails per batch (1-100,000) |
Request Example
{
"scheduledAt": "tomorrow 10am",
"batchSize": 2000
}Response Example
{
"success": true
}Pause Campaign
Pause a currently running campaign. The campaign will stop sending and can be resumed later.
Endpoint: POST /v1/campaigns/{campaignId}/pause
Path Parameters
| Parameter | Type | Description |
|---|---|---|
campaignId | string | The campaign ID (e.g., cmp_123) |
Response Example
{
"success": true
}Resume Campaign
Resume a paused campaign. Sending will continue from where it left off.
Endpoint: POST /v1/campaigns/{campaignId}/resume
Path Parameters
| Parameter | Type | Description |
|---|---|---|
campaignId | string | The campaign ID (e.g., cmp_123) |
Response Example
{
"success": true
}Best Practices
Unsubscribe Link Requirement
[!WARNING] All campaigns MUST include the
{{unsent_unsubscribe_url}}placeholder in your HTML or content. This ensures compliance with email regulations (CAN-SPAM, GDPR) and provides recipients with an easy way to opt out.
<!-- Required: Include this in every campaign -->
<p style="text-align: center; margin-top: 40px;">
<a href="{{unsent_unsubscribe_url}}" style="color: #666; text-decoration: underline;">
Unsubscribe from these emails
</a>
</p>Batch Sending
For large campaigns, use batch sending to control your sending rate and improve deliverability:
- Small campaigns (< 1,000): No batching needed
- Medium campaigns (1,000 - 10,000): Use
batchSize: 500-1000 - Large campaigns (> 10,000): Use
batchSize: 1000-2000
Scheduling Tips
- Schedule campaigns during optimal engagement times (typically weekday mornings)
- Use natural language for convenience:
"tomorrow 9am","next tuesday 10:30" - Avoid scheduling during weekends unless your audience engages then
- Consider time zones of your recipients
Campaign Personalization
Use contact properties to personalize your campaigns with dynamic content:
<html>
<body>
<h1>Hi {{firstName}} {{lastName}}!</h1>
<p>Dear {{firstName}},</p>
<p>As a valued {{properties.tier}} member since {{properties.joinDate}},
you have access to exclusive benefits.</p>
<p>Your account email: {{email}}</p>
<!-- Required unsubscribe link -->
<p><a href="{{unsent_unsubscribe_url}}">Unsubscribe</a></p>
</body>
</html>Available Template Variables
{{firstName}}- Contact's first name{{lastName}}- Contact's last name{{email}}- Contact's email address{{properties.KEY}}- Any custom contact property{{unsent_unsubscribe_url}}- Unsubscribe link (required)