Broadcasts
One email to many people, such as a product update. An API key can only draft a broadcast: it waits in awaiting_approval until a person approves it at approval_url in the web app. Give that link to the founder.
After approval Mailpark sends to a small sample first (per trust level), waits, checks bounces and complaints, then sends the rest. If something looks wrong the broadcast is held with a hold_reason and hold_fix.
type Broadcast = {
id: string; name: string; subject: string;
template: string | null; html: string;
topic: string;
audience_filter: AudienceFilter; audience_count: number;
sequence_id: string | null; // enrol recipients in a sequence instead
send_at: string | null; // null = send on approval
status: "draft" | "awaiting_approval" | "scheduled" | "test_sending"
| "sending" | "held" | "sent" | "cancelled" | "rejected";
approval_url: string;
hold_reason: string | null; hold_fix: string | null;
test_send: { enabled: boolean; sample_size: number; sent: number; result: "pending" | "healthy" | "unhealthy" | null; … };
stats: { sent: number; delivered: number; opened: number; clicked: number; bounced: number; complained: number; unsubscribed: number };
created_by: { actor_type: "user" | "api_key"; actor_id: string; actor_name: string };
approved_by: { user_id: string; name: string; at: string } | null;
created_at: string; updated_at: string;
};
type AudienceFilter = { // all parts are ANDed
lists?: string[]; // on at least one of these lists
topic?: string; // subscribed to the topic
fields?: Record<string, string | number | boolean>;
event?: { name: string; within_days?: number; did_not?: boolean };
};Draft a broadcast
/v1/broadcastsCreates a broadcast that waits for a person to approve it. The response's approval_url is the page where they do: always pass it on.
broadcasts:draftBody
namestringrequiredInternal name.
templatestringA template key. Or send
html, orsequence_id.htmlstringInline HTML instead of a template.
subjectstringOverrides the template's subject.
dataobjectValues for the template's variables.
topicstringRecipients unsubscribed from this topic are skipped.
audience_filterobjectWho gets it:
lists,topic,fields,event. See the Broadcast object above.sequence_idstringEnrol the audience in this sequence instead of sending one email.
send_atstringISO-8601 time to send. Default: on approval.
- The status is always
awaiting_approval. API keys can't approve, reject or release broadcasts.
curl -X POST https://api.mailpark.io/v1/broadcasts \
-H "Authorization: Bearer $MAILPARK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "October product update",
"template": "product-update",
"subject": "What'\''s new in Acme: October",
"data": {
"headline": "Dark mode is here"
},
"topic": "product-updates",
"audience_filter": {
"event": {
"name": "signed_up",
"within_days": 90
}
}
}'{
"id": "bc_oct",
"name": "October product update",
"subject": "What's new in Acme: October",
"template": "product-update",
"html": "<!doctype html><html>…</html>",
"topic": "product-updates",
"audience_filter": {
"event": {
"name": "signed_up",
"within_days": 90
}
},
"audience_count": 1240,
"sequence_id": null,
"enrolled": 0,
"send_at": null,
"status": "awaiting_approval",
"approval_url": "https://app.mailpark.io/campaigns/bc_oct",
"hold_reason": null,
"hold_fix": null,
"test_send": {
"enabled": true,
"sample_size": 62,
"sent": 0,
"bounced": 0,
"complained": 0,
"wait_minutes": 60,
"result": null
},
"stats": {
"sent": 0,
"delivered": 0,
"opened": 0,
"clicked": 0,
"bounced": 0,
"complained": 0,
"unsubscribed": 0
},
"created_by": {
"actor_type": "api_key",
"actor_id": "key_8Hq2",
"actor_name": "Claude Code"
},
"approved_by": null,
"created_at": "2026-10-22T10:02:11Z",
"updated_at": "2026-10-22T10:02:11Z"
}List broadcasts
/v1/broadcastsBroadcasts, newest first.
Query parameters
statusstringe.g.
awaiting_approval,sending,held,sent.limitintegerHow many to return, 1–100. Default 50.
cursorstringThe
next_cursorfrom the previous page.
curl https://api.mailpark.io/v1/broadcasts \
-H "Authorization: Bearer $MAILPARK_API_KEY"{
"data": [
{
"id": "bc_oct",
"name": "October product update",
"subject": "What's new in Acme: October",
"template": "product-update",
"html": "<!doctype html><html>…</html>",
"topic": "product-updates",
"audience_filter": {
"event": {
"name": "signed_up",
"within_days": 90
}
},
"audience_count": 1240,
"sequence_id": null,
"enrolled": 0,
"send_at": null,
"status": "awaiting_approval",
"approval_url": "https://app.mailpark.io/campaigns/bc_oct",
"hold_reason": null,
"hold_fix": null,
"test_send": {
"enabled": true,
"sample_size": 62,
"sent": 0,
"bounced": 0,
"complained": 0,
"wait_minutes": 60,
"result": null
},
"stats": {
"sent": 0,
"delivered": 0,
"opened": 0,
"clicked": 0,
"bounced": 0,
"complained": 0,
"unsubscribed": 0
},
"created_by": {
"actor_type": "api_key",
"actor_id": "key_8Hq2",
"actor_name": "Claude Code"
},
"approved_by": null,
"created_at": "2026-10-22T10:02:11Z",
"updated_at": "2026-10-22T10:02:11Z"
}
],
"next_cursor": null
}Get a broadcast
/v1/broadcasts/{id}Status, test-send result, hold reason and stats.
Path parameters
idstringrequiredbc_…
curl https://api.mailpark.io/v1/broadcasts/bc_oct \
-H "Authorization: Bearer $MAILPARK_API_KEY"{
"id": "bc_oct",
"name": "October product update",
"subject": "What's new in Acme: October",
"template": "product-update",
"html": "<!doctype html><html>…</html>",
"topic": "product-updates",
"audience_filter": {
"event": {
"name": "signed_up",
"within_days": 90
}
},
"audience_count": 1240,
"sequence_id": null,
"enrolled": 0,
"send_at": null,
"status": "awaiting_approval",
"approval_url": "https://app.mailpark.io/campaigns/bc_oct",
"hold_reason": null,
"hold_fix": null,
"test_send": {
"enabled": true,
"sample_size": 62,
"sent": 0,
"bounced": 0,
"complained": 0,
"wait_minutes": 60,
"result": null
},
"stats": {
"sent": 0,
"delivered": 0,
"opened": 0,
"clicked": 0,
"bounced": 0,
"complained": 0,
"unsubscribed": 0
},
"created_by": {
"actor_type": "api_key",
"actor_id": "key_8Hq2",
"actor_name": "Claude Code"
},
"approved_by": null,
"created_at": "2026-10-22T10:02:11Z",
"updated_at": "2026-10-22T10:02:11Z"
}Update a broadcast
/v1/broadcasts/{id}Changes a draft. Only while it is draft or awaiting_approval.
Path parameters
idstringrequiredbc_…
Body
namestringInternal name.
subjectstringSubject line.
dataobjectTemplate values.
audience_filterobjectWho gets it.
send_atstringWhen to send.
curl -X PATCH https://api.mailpark.io/v1/broadcasts/bc_oct \
-H "Authorization: Bearer $MAILPARK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"subject": "New in Acme: dark mode"
}'{
"id": "bc_oct",
"name": "October product update",
"subject": "New in Acme: dark mode",
"template": "product-update",
"html": "<!doctype html><html>…</html>",
"topic": "product-updates",
"audience_filter": {
"event": {
"name": "signed_up",
"within_days": 90
}
},
"audience_count": 1240,
"sequence_id": null,
"enrolled": 0,
"send_at": null,
"status": "awaiting_approval",
"approval_url": "https://app.mailpark.io/campaigns/bc_oct",
"hold_reason": null,
"hold_fix": null,
"test_send": {
"enabled": true,
"sample_size": 62,
"sent": 0,
"bounced": 0,
"complained": 0,
"wait_minutes": 60,
"result": null
},
"stats": {
"sent": 0,
"delivered": 0,
"opened": 0,
"clicked": 0,
"bounced": 0,
"complained": 0,
"unsubscribed": 0
},
"created_by": {
"actor_type": "api_key",
"actor_id": "key_8Hq2",
"actor_name": "Claude Code"
},
"approved_by": null,
"created_at": "2026-10-22T10:02:11Z",
"updated_at": "2026-10-22T10:02:11Z"
}Cancel a broadcast
/v1/broadcasts/{id}/cancelStops a broadcast that hasn't finished. Emails already sent stay sent.
Path parameters
idstringrequiredbc_…
curl -X POST https://api.mailpark.io/v1/broadcasts/bc_oct/cancel \
-H "Authorization: Bearer $MAILPARK_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'{
"id": "bc_oct",
"name": "October product update",
"subject": "What's new in Acme: October",
"template": "product-update",
"html": "<!doctype html><html>…</html>",
"topic": "product-updates",
"audience_filter": {
"event": {
"name": "signed_up",
"within_days": 90
}
},
"audience_count": 1240,
"sequence_id": null,
"enrolled": 0,
"send_at": null,
"status": "cancelled",
"approval_url": "https://app.mailpark.io/campaigns/bc_oct",
"hold_reason": null,
"hold_fix": null,
"test_send": {
"enabled": true,
"sample_size": 62,
"sent": 0,
"bounced": 0,
"complained": 0,
"wait_minutes": 60,
"result": null
},
"stats": {
"sent": 0,
"delivered": 0,
"opened": 0,
"clicked": 0,
"bounced": 0,
"complained": 0,
"unsubscribed": 0
},
"created_by": {
"actor_type": "api_key",
"actor_id": "key_8Hq2",
"actor_name": "Claude Code"
},
"approved_by": null,
"created_at": "2026-10-22T10:02:11Z",
"updated_at": "2026-10-22T10:02:11Z"
}Preview an audience
/v1/broadcasts/audience-previewHow many contacts a filter reaches, with a sample. Opted-out contacts are already left out.
Body
audience_filterobjectrequired{ lists?, topic?, fields?, event? }topicstringThe broadcast's topic.
curl -X POST https://api.mailpark.io/v1/broadcasts/audience-preview \
-H "Authorization: Bearer $MAILPARK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"audience_filter": {
"lists": [
"lst_beta"
]
},
"topic": "product-updates"
}'{
"count": 40,
"sample": [
{
"id": "con_7Yt1",
"email": "jane@example.com"
}
]
}