Campaigns
Create, manage, and send email marketing campaigns
Campaigns are bulk email sends to a segment of your contacts. Campaigns support scheduling, tracking, and analytics.
Auth: API key with campaigns scope.
Endpoints
| Method | Path | Description |
|---|---|---|
GET | /api/v1/campaigns | List campaigns |
POST | /api/v1/campaigns | Create a campaign |
GET | /api/v1/campaigns/:id | Get a campaign |
PATCH | /api/v1/campaigns/:id | Update a campaign |
DELETE | /api/v1/campaigns/:id | Delete a draft campaign |
POST | /api/v1/campaigns/:id/send | Send or schedule a campaign |
List campaigns
/mail/v1/campaignsList campaigns with optional status filter.
Query parameters
statusstringqueryFilter: draft, scheduled, sending, sent, failed.
pagenumberquerydefault: 1Page number.
per_pagenumberquerydefault: 20Per page (max 50).
Response fields
successbooleantrue when the request succeeded.
campaignsArray<Campaign>The page of campaigns. Each includes id, name, subject, status, segment_id, total_recipients, total_sent, total_opened, total_clicked, total_bounced, sent_at, and created_at.
paginationobjectPagination metadata: page, per_page, total.
{
"success": true,
"campaigns": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "February Newsletter",
"subject": "What's new this month",
"status": "sent",
"segment_id": "...",
"total_recipients": 5000,
"total_sent": 5000,
"total_opened": 1250,
"total_clicked": 340,
"total_bounced": 12,
"sent_at": "2026-02-01T10:00:00Z",
"created_at": "2026-01-28T09:00:00Z"
}
],
"pagination": { "page": 1, "per_page": 20, "total": 8 }
}Create a campaign
/mail/v1/campaignsCreate a new campaign. Plan limits apply.
Request body
namestringbodyrequiredInternal name.
subjectstringbodyrequiredEmail subject line (supports {{variables}}).
from_namestringbodySender display name.
from_emailstringbodyrequiredMust be a verified account.
reply_tostringbodyReply-to address.
segment_idstringbodyrequiredTarget audience segment.
template_idstringbodyUse a template instead of inline HTML. Provide template_id or body_html (one required).
body_htmlstringbodyInline HTML body. Provide template_id or body_html (one required).
body_textstringbodyPlain text fallback (recommended).
Response fields
successbooleantrue when the campaign was created.
campaignobjectThe created campaign, including id, name, and status.
{
"name": "February Newsletter",
"subject": "What's new this month 🚀",
"from_name": "Misar Team",
"from_email": "[email protected]",
"reply_to": "[email protected]",
"segment_id": "550e8400-e29b-41d4-a716-446655440001",
"template_id": "550e8400-e29b-41d4-a716-446655440002",
"body_html": "<h1>Hello {{first_name}}!</h1>",
"body_text": "Hello {{first_name}}!"
}{
"success": true,
"campaign": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "February Newsletter",
"status": "draft"
}
}Errors
403— Campaign limit reached for your plan
Update a campaign
/mail/v1/campaigns/:idUpdate a draft campaign. Cannot update campaigns that are sending or sent. Any subset of campaign fields may be sent.
Path parameters
idstringpathrequiredID of the campaign to update.
Request body
subjectstringbodyUpdated subject line.
body_htmlstringbodyUpdated HTML content.
{
"subject": "Updated subject line",
"body_html": "<h1>Updated content</h1>"
}Delete a campaign
/mail/v1/campaigns/:idDelete a draft campaign. Cannot delete scheduled, sending, or sent campaigns.
Path parameters
idstringpathrequiredID of the draft campaign to delete.
curl -X DELETE https://api.misar.io/mail/v1/campaigns/550e8400-e29b-41d4-a716-446655440000 \
-H "Authorization: Bearer msk_your_key"Send or schedule a campaign
/mail/v1/campaigns/:id/sendSend or schedule a campaign. The campaign must be in draft status. Omit send_at to send immediately.
Path parameters
idstringpathrequiredID of the draft campaign.
Request body
send_atstringbodyISO-8601 time to schedule the send. Omit to send immediately.
Response fields
successbooleantrue when the send was accepted.
campaign_idstringID of the campaign.
statusstringResulting status, e.g. sending.
scheduled_atstringScheduled send time, or null for immediate sends.
estimated_recipientsnumberEstimated number of recipients.
{
"send_at": "2026-03-01T10:00:00Z"
}{
"success": true,
"campaign_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "sending",
"scheduled_at": null,
"estimated_recipients": 5000
}Errors
400— Campaign is not indraftstatus400—from_emailis not a verified account429— Daily or monthly send limit would be exceeded403— Insufficient campaign ownership
Campaign Sub-Endpoints
These endpoints operate on an existing campaign by ID.
Get campaign sends
/mail/v1/campaigns/:id/sendsGet per-recipient send records for a campaign with status tracking.
Auth: API key with campaigns scope.
Path parameters
idstringpathrequiredID of the campaign.
Query parameters
pagenumberquerydefault: 1Page number.
limitnumberquerydefault: 50Results per page (max 100).
statusstringqueryFilter: sent, delivered, opened, clicked, bounced, complained, unsubscribed, failed.
Response fields
successbooleantrue when the request succeeded.
campaignobjectSummary: id, name, status, total_sent, total_failed.
breakdownobjectAggregate counts: sent, bounced, opened, clicked, failed.
dataArray<Send>Per-recipient send records, each with id, email, contact_id, status, sent_at, opened_at, clicked_at, bounced_at, and error_message.
paginationobjectPagination metadata: page, limit, total, totalPages.
{
"success": true,
"campaign": { "id": "...", "name": "Spring Sale", "status": "sent", "total_sent": 5200, "total_failed": 3 },
"breakdown": { "sent": 5197, "bounced": 48, "opened": 2038, "clicked": 510, "failed": 3 },
"data": [
{
"id": "send_...",
"email": "[email protected]",
"contact_id": "...",
"status": "opened",
"sent_at": "2026-04-01T09:01:00Z",
"opened_at": "2026-04-01T09:15:00Z",
"clicked_at": null,
"bounced_at": null,
"error_message": null
}
],
"pagination": { "page": 1, "limit": 50, "total": 5200, "totalPages": 104 }
}Create an A/B test variant
/mail/v1/campaigns/:id/ab-testsCreate an A/B test variant for a campaign.
Auth: API key with campaigns scope. Plan: Pro+.
Path parameters
idstringpathrequiredID of the campaign.
Request body
variantstringbodyrequiredLabel e.g. "B", "C".
test_typestringbodydefault: contentcontent, subject, send_time, from_name, preheader.
subjectstringbodyVariant subject (for test_type: subject).
preheaderstringbodyVariant preheader (for test_type: preheader).
body_htmlstringbodyVariant HTML (for test_type: content).
from_namestringbodyVariant sender name.
send_percentnumberbodydefault: 50% of audience for this variant (1-99).
auto_select_winnerbooleanbodyAuto-select winner after wait.
winner_wait_hoursnumberbodydefault: 4Hours to wait (1-168).
curl -X POST https://api.misar.io/mail/v1/campaigns/camp_abc123/ab-tests \
-H "Authorization: Bearer msk_your_key" \
-H "Content-Type: application/json" \
-d '{
"variant": "B",
"test_type": "subject",
"subject": "Don'\''t miss our Spring Sale 🌸",
"send_percent": 50,
"auto_select_winner": true,
"winner_wait_hours": 4
}'Optimize send time
/mail/v1/campaigns/:id/optimizeAI-powered send time optimization. Analyzes past open patterns to recommend the best send window. Calling this endpoint also updates the campaign's scheduled_at to the recommended time.
Auth: API key with campaigns scope. Plan: Pro+.
Path parameters
idstringpathrequiredID of the campaign.
Response fields
successbooleantrue when the request succeeded.
recommendationobjectRecommended window: day_of_week, hour_utc, confidence, basis.
scheduledAtstringISO-8601 time the campaign was scheduled to.
{
"success": true,
"recommendation": {
"day_of_week": "Tuesday",
"hour_utc": 9,
"confidence": 0.87,
"basis": "Your subscribers have 40% higher open rates on Tuesday 9-10am UTC"
},
"scheduledAt": "2026-06-03T09:00:00Z"
}Predict campaign performance
/mail/v1/campaigns/:id/predictPredict expected open and click rates before sending based on subject line and segment characteristics.
Auth: API key. Plan: Pro+.
Path parameters
idstringpathrequiredID of the campaign.
Response fields
successbooleantrue when the request succeeded.
predictionsobjectPredicted metrics: expectedOpenRate, expectedClickRate, confidence, factors.
{
"success": true,
"predictions": {
"expectedOpenRate": 0.34,
"expectedClickRate": 0.08,
"confidence": 0.72,
"factors": ["subject_length_optimal", "good_send_time", "segment_recently_engaged"]
}
}Rewrite campaign content
/mail/v1/campaigns/:id/rewriteAI-rewrite the campaign content with spam-word filtering and deliverability checks. Updates the campaign body in-place.
Auth: API key. Plan: Pro+.
Path parameters
idstringpathrequiredID of the campaign.
Request body
instructionsstringbodyRewrite instructions.
tonestringbodyDesired tone, e.g. friendly.
Response fields
successbooleantrue when the rewrite succeeded.
dataobjectRewritten content: subject, html, preheader.
{
"instructions": "Make it more conversational and reduce the subject line length",
"tone": "friendly"
}{
"success": true,
"data": {
"subject": "Spring is here — don't miss it",
"html": "<p>...</p>",
"preheader": "Your exclusive spring offer inside"
}
}Save as template
/mail/v1/campaigns/:id/save-as-templateSave a campaign as a reusable template.
Auth: API key.
Path parameters
idstringpathrequiredID of the campaign.
Request body
namestringbodyTemplate name.
descriptionstringbodyTemplate description.
Response fields
successbooleantrue when the template was created.
templateobjectThe created template: id, name, created_at.
{
"name": "Spring Sale Template",
"description": "Seasonal sale email format"
}{
"success": true,
"template": {
"id": "tpl_abc123",
"name": "Spring Sale Template",
"created_at": "2026-05-27T10:00:00Z"
}
}Configure reply webhook
/mail/v1/campaigns/:id/reply-webhookConfigure a webhook URL to receive replies to this campaign (inbound replies forwarded in real time). Replies are POSTed to your URL with payload: { "campaign_id", "from_email", "from_name", "subject", "text", "html", "received_at" }.
Auth: API key.
Path parameters
idstringpathrequiredID of the campaign.
Request body
webhook_urlstringbodyURL to receive inbound replies.
secretstringbodySigning secret for verifying webhook payloads.
{
"webhook_url": "https://yourapp.com/webhooks/replies",
"secret": "whsec_..."
}