Broadcasts
One-to-many sends: draft a broadcast, edit it, and send it now or on a schedule.
Auth: Session token · Base URL:
https://api.mailkite.dev
Endpoints
Each row expands to its request and response schema. The address bar follows along, so any endpoint can be linked to directly.
GET /api/broadcasts List your broadcasts (one-to-many sends) with status and send stats.
List your broadcasts (one-to-many sends) with status and send stats.
One broadcast (bct_…): content + audience + send state. Only drafts are editable; send() flips a draft to 'scheduled' or 'sending' and the per-recipient ledger tracks fan-out.
| Field | Type | Notes |
|---|---|---|
| id req | string | Broadcast id (bct_…). |
| user_id req | string | Owning account (usr_…). |
| name req | string | Internal name shown in the dashboard list. |
| from_addr req | string | Sender, on an outbound-verified domain you own. May carry a display name. |
| reply_to | string · null | Reply-To address, when set. |
| subject req | string | Subject line. |
| preview | string · null | Inbox preview text (the snippet next to the subject). |
| audience req | string | Audience selection as a JSON string: { "type": "all" | "list" | "filter", "id"?: … }. |
| template_id | string · null | Template the content comes from (tpl_… / base_…), when content isn't inline. |
| html | string · null | Inline HTML body, when not using a template. |
| text | string · null | Inline plain-text body, when not using a template. |
| footer_address | string · null | Physical postal address for the CAN-SPAM footer. Prefilled from the account when not set. |
| status req | "draft" · "scheduled" · "sending" · "sent" · "canceled" · "failed" | Send lifecycle state. |
| scheduled_at | integer · null | When a scheduled broadcast will send, in Unix epoch milliseconds (UTC); null when it has never happened. |
| audience_count | integer · null | Snapshot of the audience size taken at send/schedule time; null for drafts. |
| sent_count req | integer | Recipients sent so far. |
| fail_count req | integer | Recipients failed so far. |
| sent_at | integer · null | When sending completed, in Unix epoch milliseconds (UTC); null when it has never happened. |
| created_at req | integer | When the broadcast was created, in Unix epoch milliseconds (UTC). |
| updated_at req | integer | When the broadcast last changed, in Unix epoch milliseconds (UTC). |
An actual array of results, recorded from the conformance suite.
[
{
"id": "bct_3Jf7HkPw",
"user_id": "usr_7Fj3MnQw",
"name": "July product update",
"from_addr": "MailKite <hello@myapp.ai>",
"reply_to": null,
"subject": "What's new in July",
"preview": null,
"audience": "{\"type\":\"list\",\"id\":\"lst_5Wd9JqRs\"}",
"template_id": null,
"html": "<h1>What's new</h1>",
"text": "What's new",
"footer_address": "548 Market St, San Francisco, CA",
"status": "draft",
"scheduled_at": null,
"audience_count": null,
"sent_count": 0,
"fail_count": 0,
"sent_at": null,
"created_at": 1769731200000,
"updated_at": 1769731200000
}
] {
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://api.mailkite.dev/v1/schemas/broadcast.json",
"title": "Broadcast",
"description": "One broadcast (bct_…): content + audience + send state. Only drafts are editable; send() flips a draft to 'scheduled' or 'sending' and the per-recipient ledger tracks fan-out.",
"type": "object",
"required": [
"id",
"user_id",
"name",
"from_addr",
"subject",
"audience",
"status",
"sent_count",
"fail_count",
"created_at",
"updated_at"
],
"properties": {
"id": {
"type": "string",
"description": "Broadcast id (bct_…).",
"examples": [
"bct_3Jf7HkPw"
]
},
"user_id": {
"type": "string",
"description": "Owning account (usr_…).",
"examples": [
"usr_7Fj3MnQw"
]
},
"name": {
"type": "string",
"description": "Internal name shown in the dashboard list.",
"examples": [
"July product update"
]
},
"from_addr": {
"type": "string",
"description": "Sender, on an outbound-verified domain you own. May carry a display name.",
"examples": [
"MailKite <hello@myapp.ai>"
]
},
"reply_to": {
"type": [
"string",
"null"
],
"description": "Reply-To address, when set."
},
"subject": {
"type": "string",
"description": "Subject line.",
"examples": [
"What's new in July"
]
},
"preview": {
"type": [
"string",
"null"
],
"description": "Inbox preview text (the snippet next to the subject)."
},
"audience": {
"type": "string",
"description": "Audience selection as a JSON string: { \"type\": \"all\" | \"list\" | \"filter\", \"id\"?: … }.",
"examples": [
"{\"type\":\"list\",\"id\":\"lst_5Wd9JqRs\"}"
]
},
"template_id": {
"type": [
"string",
"null"
],
"description": "Template the content comes from (tpl_… / base_…), when content isn't inline."
},
"html": {
"type": [
"string",
"null"
],
"description": "Inline HTML body, when not using a template."
},
"text": {
"type": [
"string",
"null"
],
"description": "Inline plain-text body, when not using a template."
},
"footer_address": {
"type": [
"string",
"null"
],
"description": "Physical postal address for the CAN-SPAM footer. Prefilled from the account when not set."
},
"status": {
"type": "string",
"enum": [
"draft",
"scheduled",
"sending",
"sent",
"canceled",
"failed"
],
"description": "Send lifecycle state."
},
"scheduled_at": {
"type": [
"integer",
"null"
],
"description": "When a scheduled broadcast will send, in Unix epoch milliseconds (UTC); null when it has never happened.",
"examples": [
1769731200000
]
},
"audience_count": {
"type": [
"integer",
"null"
],
"description": "Snapshot of the audience size taken at send/schedule time; null for drafts.",
"examples": [
1284
]
},
"sent_count": {
"type": "integer",
"description": "Recipients sent so far.",
"examples": [
0
]
},
"fail_count": {
"type": "integer",
"description": "Recipients failed so far.",
"examples": [
0
]
},
"sent_at": {
"type": [
"integer",
"null"
],
"description": "When sending completed, in Unix epoch milliseconds (UTC); null when it has never happened.",
"examples": [
1769731200000
]
},
"created_at": {
"type": "integer",
"description": "When the broadcast was created, in Unix epoch milliseconds (UTC).",
"examples": [
1769731200000
]
},
"updated_at": {
"type": "integer",
"description": "When the broadcast last changed, in Unix epoch milliseconds (UTC).",
"examples": [
1769731200000
]
}
}
} POST /api/broadcasts Create a broadcast draft. `from` is required; set `audience` to { type: "all" } or { type: "list", id: "lst_…" }. Returns the broadcast with its id (bct_…). Send it with sendBroadcast.
Create a broadcast draft. `from` is required; set `audience` to { type: "all" } or { type: "list", id: "lst_…" }. Returns the broadcast with its id (bct_…). Send it with sendBroadcast.
Request body
create-broadcast-request.json| Field | Type | Notes |
|---|---|---|
| name | string | |
| from req | string | |
| replyTo | string | |
| subject | string | |
| preview | string | |
| audience | object | |
| audience.type | "all" · "list" · "filter" | |
| audience.id | string | |
| audience.query | string | |
| templateId | string | |
| html | string | |
| text | string | |
| footerAddress | string |
The smallest body that makes this call — every other field is optional.
{
"from": "news@app.mailkite.dev",
"subject": "Launch week",
"audience": {
"type": "all"
},
"html": "<h1>We shipped</h1>"
} {
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://api.mailkite.dev/v1/schemas/create-broadcast-request.json",
"title": "Create broadcast request body",
"type": "object",
"required": [
"from"
],
"additionalProperties": false,
"properties": {
"name": {
"type": "string"
},
"from": {
"type": "string"
},
"replyTo": {
"type": "string"
},
"subject": {
"type": "string"
},
"preview": {
"type": "string"
},
"audience": {
"type": "object",
"additionalProperties": false,
"properties": {
"type": {
"type": "string",
"enum": [
"all",
"list",
"filter"
]
},
"id": {
"type": "string"
},
"query": {
"type": "string"
}
}
},
"templateId": {
"type": "string"
},
"html": {
"type": "string"
},
"text": {
"type": "string"
},
"footerAddress": {
"type": "string"
}
}
} Response body
broadcast.jsonOne broadcast (bct_…): content + audience + send state. Only drafts are editable; send() flips a draft to 'scheduled' or 'sending' and the per-recipient ledger tracks fan-out.
| Field | Type | Notes |
|---|---|---|
| id req | string | Broadcast id (bct_…). |
| user_id req | string | Owning account (usr_…). |
| name req | string | Internal name shown in the dashboard list. |
| from_addr req | string | Sender, on an outbound-verified domain you own. May carry a display name. |
| reply_to | string · null | Reply-To address, when set. |
| subject req | string | Subject line. |
| preview | string · null | Inbox preview text (the snippet next to the subject). |
| audience req | string | Audience selection as a JSON string: { "type": "all" | "list" | "filter", "id"?: … }. |
| template_id | string · null | Template the content comes from (tpl_… / base_…), when content isn't inline. |
| html | string · null | Inline HTML body, when not using a template. |
| text | string · null | Inline plain-text body, when not using a template. |
| footer_address | string · null | Physical postal address for the CAN-SPAM footer. Prefilled from the account when not set. |
| status req | "draft" · "scheduled" · "sending" · "sent" · "canceled" · "failed" | Send lifecycle state. |
| scheduled_at | integer · null | When a scheduled broadcast will send, in Unix epoch milliseconds (UTC); null when it has never happened. |
| audience_count | integer · null | Snapshot of the audience size taken at send/schedule time; null for drafts. |
| sent_count req | integer | Recipients sent so far. |
| fail_count req | integer | Recipients failed so far. |
| sent_at | integer · null | When sending completed, in Unix epoch milliseconds (UTC); null when it has never happened. |
| created_at req | integer | When the broadcast was created, in Unix epoch milliseconds (UTC). |
| updated_at req | integer | When the broadcast last changed, in Unix epoch milliseconds (UTC). |
An actual response, recorded from the conformance suite.
{
"id": "bct_3Jf7HkPw",
"user_id": "usr_7Fj3MnQw",
"name": "July product update",
"from_addr": "MailKite <hello@myapp.ai>",
"reply_to": null,
"subject": "What's new in July",
"preview": null,
"audience": "{\"type\":\"list\",\"id\":\"lst_5Wd9JqRs\"}",
"template_id": null,
"html": "<h1>What's new</h1>",
"text": "What's new",
"footer_address": "548 Market St, San Francisco, CA",
"status": "draft",
"scheduled_at": null,
"audience_count": null,
"sent_count": 0,
"fail_count": 0,
"sent_at": null,
"created_at": 1769731200000,
"updated_at": 1769731200000
} {
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://api.mailkite.dev/v1/schemas/broadcast.json",
"title": "Broadcast",
"description": "One broadcast (bct_…): content + audience + send state. Only drafts are editable; send() flips a draft to 'scheduled' or 'sending' and the per-recipient ledger tracks fan-out.",
"type": "object",
"required": [
"id",
"user_id",
"name",
"from_addr",
"subject",
"audience",
"status",
"sent_count",
"fail_count",
"created_at",
"updated_at"
],
"properties": {
"id": {
"type": "string",
"description": "Broadcast id (bct_…).",
"examples": [
"bct_3Jf7HkPw"
]
},
"user_id": {
"type": "string",
"description": "Owning account (usr_…).",
"examples": [
"usr_7Fj3MnQw"
]
},
"name": {
"type": "string",
"description": "Internal name shown in the dashboard list.",
"examples": [
"July product update"
]
},
"from_addr": {
"type": "string",
"description": "Sender, on an outbound-verified domain you own. May carry a display name.",
"examples": [
"MailKite <hello@myapp.ai>"
]
},
"reply_to": {
"type": [
"string",
"null"
],
"description": "Reply-To address, when set."
},
"subject": {
"type": "string",
"description": "Subject line.",
"examples": [
"What's new in July"
]
},
"preview": {
"type": [
"string",
"null"
],
"description": "Inbox preview text (the snippet next to the subject)."
},
"audience": {
"type": "string",
"description": "Audience selection as a JSON string: { \"type\": \"all\" | \"list\" | \"filter\", \"id\"?: … }.",
"examples": [
"{\"type\":\"list\",\"id\":\"lst_5Wd9JqRs\"}"
]
},
"template_id": {
"type": [
"string",
"null"
],
"description": "Template the content comes from (tpl_… / base_…), when content isn't inline."
},
"html": {
"type": [
"string",
"null"
],
"description": "Inline HTML body, when not using a template."
},
"text": {
"type": [
"string",
"null"
],
"description": "Inline plain-text body, when not using a template."
},
"footer_address": {
"type": [
"string",
"null"
],
"description": "Physical postal address for the CAN-SPAM footer. Prefilled from the account when not set."
},
"status": {
"type": "string",
"enum": [
"draft",
"scheduled",
"sending",
"sent",
"canceled",
"failed"
],
"description": "Send lifecycle state."
},
"scheduled_at": {
"type": [
"integer",
"null"
],
"description": "When a scheduled broadcast will send, in Unix epoch milliseconds (UTC); null when it has never happened.",
"examples": [
1769731200000
]
},
"audience_count": {
"type": [
"integer",
"null"
],
"description": "Snapshot of the audience size taken at send/schedule time; null for drafts.",
"examples": [
1284
]
},
"sent_count": {
"type": "integer",
"description": "Recipients sent so far.",
"examples": [
0
]
},
"fail_count": {
"type": "integer",
"description": "Recipients failed so far.",
"examples": [
0
]
},
"sent_at": {
"type": [
"integer",
"null"
],
"description": "When sending completed, in Unix epoch milliseconds (UTC); null when it has never happened.",
"examples": [
1769731200000
]
},
"created_at": {
"type": "integer",
"description": "When the broadcast was created, in Unix epoch milliseconds (UTC).",
"examples": [
1769731200000
]
},
"updated_at": {
"type": "integer",
"description": "When the broadcast last changed, in Unix epoch milliseconds (UTC).",
"examples": [
1769731200000
]
}
}
} GET /api/broadcasts/:id Get one broadcast with its status and recipient summary.
Get one broadcast with its status and recipient summary.
Response body
broadcast.jsonOne broadcast (bct_…): content + audience + send state. Only drafts are editable; send() flips a draft to 'scheduled' or 'sending' and the per-recipient ledger tracks fan-out.
| Field | Type | Notes |
|---|---|---|
| id req | string | Broadcast id (bct_…). |
| user_id req | string | Owning account (usr_…). |
| name req | string | Internal name shown in the dashboard list. |
| from_addr req | string | Sender, on an outbound-verified domain you own. May carry a display name. |
| reply_to | string · null | Reply-To address, when set. |
| subject req | string | Subject line. |
| preview | string · null | Inbox preview text (the snippet next to the subject). |
| audience req | string | Audience selection as a JSON string: { "type": "all" | "list" | "filter", "id"?: … }. |
| template_id | string · null | Template the content comes from (tpl_… / base_…), when content isn't inline. |
| html | string · null | Inline HTML body, when not using a template. |
| text | string · null | Inline plain-text body, when not using a template. |
| footer_address | string · null | Physical postal address for the CAN-SPAM footer. Prefilled from the account when not set. |
| status req | "draft" · "scheduled" · "sending" · "sent" · "canceled" · "failed" | Send lifecycle state. |
| scheduled_at | integer · null | When a scheduled broadcast will send, in Unix epoch milliseconds (UTC); null when it has never happened. |
| audience_count | integer · null | Snapshot of the audience size taken at send/schedule time; null for drafts. |
| sent_count req | integer | Recipients sent so far. |
| fail_count req | integer | Recipients failed so far. |
| sent_at | integer · null | When sending completed, in Unix epoch milliseconds (UTC); null when it has never happened. |
| created_at req | integer | When the broadcast was created, in Unix epoch milliseconds (UTC). |
| updated_at req | integer | When the broadcast last changed, in Unix epoch milliseconds (UTC). |
An actual response, recorded from the conformance suite.
{
"id": "bct_3Jf7HkPw",
"user_id": "usr_7Fj3MnQw",
"name": "July product update",
"from_addr": "MailKite <hello@myapp.ai>",
"reply_to": null,
"subject": "What's new in July",
"preview": null,
"audience": "{\"type\":\"list\",\"id\":\"lst_5Wd9JqRs\"}",
"template_id": null,
"html": "<h1>What's new</h1>",
"text": "What's new",
"footer_address": "548 Market St, San Francisco, CA",
"status": "draft",
"scheduled_at": null,
"audience_count": null,
"sent_count": 0,
"fail_count": 0,
"sent_at": null,
"created_at": 1769731200000,
"updated_at": 1769731200000
} {
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://api.mailkite.dev/v1/schemas/broadcast.json",
"title": "Broadcast",
"description": "One broadcast (bct_…): content + audience + send state. Only drafts are editable; send() flips a draft to 'scheduled' or 'sending' and the per-recipient ledger tracks fan-out.",
"type": "object",
"required": [
"id",
"user_id",
"name",
"from_addr",
"subject",
"audience",
"status",
"sent_count",
"fail_count",
"created_at",
"updated_at"
],
"properties": {
"id": {
"type": "string",
"description": "Broadcast id (bct_…).",
"examples": [
"bct_3Jf7HkPw"
]
},
"user_id": {
"type": "string",
"description": "Owning account (usr_…).",
"examples": [
"usr_7Fj3MnQw"
]
},
"name": {
"type": "string",
"description": "Internal name shown in the dashboard list.",
"examples": [
"July product update"
]
},
"from_addr": {
"type": "string",
"description": "Sender, on an outbound-verified domain you own. May carry a display name.",
"examples": [
"MailKite <hello@myapp.ai>"
]
},
"reply_to": {
"type": [
"string",
"null"
],
"description": "Reply-To address, when set."
},
"subject": {
"type": "string",
"description": "Subject line.",
"examples": [
"What's new in July"
]
},
"preview": {
"type": [
"string",
"null"
],
"description": "Inbox preview text (the snippet next to the subject)."
},
"audience": {
"type": "string",
"description": "Audience selection as a JSON string: { \"type\": \"all\" | \"list\" | \"filter\", \"id\"?: … }.",
"examples": [
"{\"type\":\"list\",\"id\":\"lst_5Wd9JqRs\"}"
]
},
"template_id": {
"type": [
"string",
"null"
],
"description": "Template the content comes from (tpl_… / base_…), when content isn't inline."
},
"html": {
"type": [
"string",
"null"
],
"description": "Inline HTML body, when not using a template."
},
"text": {
"type": [
"string",
"null"
],
"description": "Inline plain-text body, when not using a template."
},
"footer_address": {
"type": [
"string",
"null"
],
"description": "Physical postal address for the CAN-SPAM footer. Prefilled from the account when not set."
},
"status": {
"type": "string",
"enum": [
"draft",
"scheduled",
"sending",
"sent",
"canceled",
"failed"
],
"description": "Send lifecycle state."
},
"scheduled_at": {
"type": [
"integer",
"null"
],
"description": "When a scheduled broadcast will send, in Unix epoch milliseconds (UTC); null when it has never happened.",
"examples": [
1769731200000
]
},
"audience_count": {
"type": [
"integer",
"null"
],
"description": "Snapshot of the audience size taken at send/schedule time; null for drafts.",
"examples": [
1284
]
},
"sent_count": {
"type": "integer",
"description": "Recipients sent so far.",
"examples": [
0
]
},
"fail_count": {
"type": "integer",
"description": "Recipients failed so far.",
"examples": [
0
]
},
"sent_at": {
"type": [
"integer",
"null"
],
"description": "When sending completed, in Unix epoch milliseconds (UTC); null when it has never happened.",
"examples": [
1769731200000
]
},
"created_at": {
"type": "integer",
"description": "When the broadcast was created, in Unix epoch milliseconds (UTC).",
"examples": [
1769731200000
]
},
"updated_at": {
"type": "integer",
"description": "When the broadcast last changed, in Unix epoch milliseconds (UTC).",
"examples": [
1769731200000
]
}
}
} PATCH /api/broadcasts/:id Edit a draft broadcast (any of from/subject/audience/html/… ). Drafts only.
Edit a draft broadcast (any of from/subject/audience/html/… ). Drafts only.
Request body
update-broadcast-request.json| Field | Type | Notes |
|---|---|---|
| name | string | |
| from | string | |
| replyTo | string | |
| subject | string | |
| preview | string | |
| audience | object | |
| audience.type | "all" · "list" · "filter" | |
| audience.id | string | |
| audience.query | string | |
| templateId | string | |
| html | string | |
| text | string | |
| footerAddress | string |
The smallest body that makes this call — every other field is optional.
{
"subject": "Launch week (final)"
} {
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://api.mailkite.dev/v1/schemas/update-broadcast-request.json",
"title": "Update broadcast request body (draft edits; all fields optional)",
"type": "object",
"additionalProperties": false,
"properties": {
"name": {
"type": "string"
},
"from": {
"type": "string"
},
"replyTo": {
"type": "string"
},
"subject": {
"type": "string"
},
"preview": {
"type": "string"
},
"audience": {
"type": "object",
"additionalProperties": false,
"properties": {
"type": {
"type": "string",
"enum": [
"all",
"list",
"filter"
]
},
"id": {
"type": "string"
},
"query": {
"type": "string"
}
}
},
"templateId": {
"type": "string"
},
"html": {
"type": "string"
},
"text": {
"type": "string"
},
"footerAddress": {
"type": "string"
}
}
} Response body
broadcast.jsonOne broadcast (bct_…): content + audience + send state. Only drafts are editable; send() flips a draft to 'scheduled' or 'sending' and the per-recipient ledger tracks fan-out.
| Field | Type | Notes |
|---|---|---|
| id req | string | Broadcast id (bct_…). |
| user_id req | string | Owning account (usr_…). |
| name req | string | Internal name shown in the dashboard list. |
| from_addr req | string | Sender, on an outbound-verified domain you own. May carry a display name. |
| reply_to | string · null | Reply-To address, when set. |
| subject req | string | Subject line. |
| preview | string · null | Inbox preview text (the snippet next to the subject). |
| audience req | string | Audience selection as a JSON string: { "type": "all" | "list" | "filter", "id"?: … }. |
| template_id | string · null | Template the content comes from (tpl_… / base_…), when content isn't inline. |
| html | string · null | Inline HTML body, when not using a template. |
| text | string · null | Inline plain-text body, when not using a template. |
| footer_address | string · null | Physical postal address for the CAN-SPAM footer. Prefilled from the account when not set. |
| status req | "draft" · "scheduled" · "sending" · "sent" · "canceled" · "failed" | Send lifecycle state. |
| scheduled_at | integer · null | When a scheduled broadcast will send, in Unix epoch milliseconds (UTC); null when it has never happened. |
| audience_count | integer · null | Snapshot of the audience size taken at send/schedule time; null for drafts. |
| sent_count req | integer | Recipients sent so far. |
| fail_count req | integer | Recipients failed so far. |
| sent_at | integer · null | When sending completed, in Unix epoch milliseconds (UTC); null when it has never happened. |
| created_at req | integer | When the broadcast was created, in Unix epoch milliseconds (UTC). |
| updated_at req | integer | When the broadcast last changed, in Unix epoch milliseconds (UTC). |
An actual response, recorded from the conformance suite.
{
"id": "bct_3Jf7HkPw",
"user_id": "usr_7Fj3MnQw",
"name": "July product update",
"from_addr": "MailKite <hello@myapp.ai>",
"reply_to": null,
"subject": "What's new in July — updated",
"preview": null,
"audience": "{\"type\":\"list\",\"id\":\"lst_5Wd9JqRs\"}",
"template_id": null,
"html": "<h1>What's new</h1>",
"text": "What's new",
"footer_address": "548 Market St, San Francisco, CA",
"status": "draft",
"scheduled_at": null,
"audience_count": null,
"sent_count": 0,
"fail_count": 0,
"sent_at": null,
"created_at": 1769731200000,
"updated_at": 1769817600000
} {
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://api.mailkite.dev/v1/schemas/broadcast.json",
"title": "Broadcast",
"description": "One broadcast (bct_…): content + audience + send state. Only drafts are editable; send() flips a draft to 'scheduled' or 'sending' and the per-recipient ledger tracks fan-out.",
"type": "object",
"required": [
"id",
"user_id",
"name",
"from_addr",
"subject",
"audience",
"status",
"sent_count",
"fail_count",
"created_at",
"updated_at"
],
"properties": {
"id": {
"type": "string",
"description": "Broadcast id (bct_…).",
"examples": [
"bct_3Jf7HkPw"
]
},
"user_id": {
"type": "string",
"description": "Owning account (usr_…).",
"examples": [
"usr_7Fj3MnQw"
]
},
"name": {
"type": "string",
"description": "Internal name shown in the dashboard list.",
"examples": [
"July product update"
]
},
"from_addr": {
"type": "string",
"description": "Sender, on an outbound-verified domain you own. May carry a display name.",
"examples": [
"MailKite <hello@myapp.ai>"
]
},
"reply_to": {
"type": [
"string",
"null"
],
"description": "Reply-To address, when set."
},
"subject": {
"type": "string",
"description": "Subject line.",
"examples": [
"What's new in July"
]
},
"preview": {
"type": [
"string",
"null"
],
"description": "Inbox preview text (the snippet next to the subject)."
},
"audience": {
"type": "string",
"description": "Audience selection as a JSON string: { \"type\": \"all\" | \"list\" | \"filter\", \"id\"?: … }.",
"examples": [
"{\"type\":\"list\",\"id\":\"lst_5Wd9JqRs\"}"
]
},
"template_id": {
"type": [
"string",
"null"
],
"description": "Template the content comes from (tpl_… / base_…), when content isn't inline."
},
"html": {
"type": [
"string",
"null"
],
"description": "Inline HTML body, when not using a template."
},
"text": {
"type": [
"string",
"null"
],
"description": "Inline plain-text body, when not using a template."
},
"footer_address": {
"type": [
"string",
"null"
],
"description": "Physical postal address for the CAN-SPAM footer. Prefilled from the account when not set."
},
"status": {
"type": "string",
"enum": [
"draft",
"scheduled",
"sending",
"sent",
"canceled",
"failed"
],
"description": "Send lifecycle state."
},
"scheduled_at": {
"type": [
"integer",
"null"
],
"description": "When a scheduled broadcast will send, in Unix epoch milliseconds (UTC); null when it has never happened.",
"examples": [
1769731200000
]
},
"audience_count": {
"type": [
"integer",
"null"
],
"description": "Snapshot of the audience size taken at send/schedule time; null for drafts.",
"examples": [
1284
]
},
"sent_count": {
"type": "integer",
"description": "Recipients sent so far.",
"examples": [
0
]
},
"fail_count": {
"type": "integer",
"description": "Recipients failed so far.",
"examples": [
0
]
},
"sent_at": {
"type": [
"integer",
"null"
],
"description": "When sending completed, in Unix epoch milliseconds (UTC); null when it has never happened.",
"examples": [
1769731200000
]
},
"created_at": {
"type": "integer",
"description": "When the broadcast was created, in Unix epoch milliseconds (UTC).",
"examples": [
1769731200000
]
},
"updated_at": {
"type": "integer",
"description": "When the broadcast last changed, in Unix epoch milliseconds (UTC).",
"examples": [
1769731200000
]
}
}
} DELETE /api/broadcasts/:id Delete a broadcast draft.
Delete a broadcast draft.
Response body
ok-response.jsonThe uniform acknowledgement for deletes and other actions with nothing else to report.
| Field | Type | Notes |
|---|---|---|
| ok req | true | Always true — a non-2xx error body is returned otherwise. |
An actual response, recorded from the conformance suite.
{
"ok": true
} {
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://api.mailkite.dev/v1/schemas/ok-response.json",
"title": "OK",
"description": "The uniform acknowledgement for deletes and other actions with nothing else to report.",
"type": "object",
"required": [
"ok"
],
"properties": {
"ok": {
"type": "boolean",
"const": true,
"description": "Always true — a non-2xx error body is returned otherwise."
}
}
} POST /api/broadcasts/:id/send Send a broadcast now, or pass an ISO 8601 `scheduledAt` to schedule it. A one-click unsubscribe is always added. Returns the status and resolved audience count.
Send a broadcast now, or pass an ISO 8601 `scheduledAt` to schedule it. A one-click unsubscribe is always added. Returns the status and resolved audience count.
Request body
send-broadcast-request.json| Field | Type | Notes |
|---|---|---|
| scheduledAt | string |
The smallest body that makes this call — every other field is optional.
{
"scheduledAt": "2026-07-01T15:00:00Z"
} {
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://api.mailkite.dev/v1/schemas/send-broadcast-request.json",
"title": "Send broadcast request body",
"type": "object",
"additionalProperties": false,
"properties": {
"scheduledAt": {
"type": "string"
}
}
} Response body
send-broadcast-response.jsonPOST /api/broadcasts/:id/send — 202 with the broadcast's new state: 'scheduled' when a future scheduledAt was given, else 'sending' (fan-out continues in the background; poll GET /api/broadcasts/:id for progress).
| Field | Type | Notes |
|---|---|---|
| id req | string | The broadcast (bct_…). |
| status req | "scheduled" · "sending" | State the broadcast moved to. |
| scheduledAt | integer | When a scheduled broadcast will send. Present only when status is 'scheduled', in Unix epoch milliseconds (UTC). |
| audienceCount req | integer | Audience size snapshotted at this moment. |
An actual response, recorded from the conformance suite.
{
"id": "bct_3Jf7HkPw",
"status": "sending",
"audienceCount": 1284
} {
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://api.mailkite.dev/v1/schemas/send-broadcast-response.json",
"title": "Send broadcast response",
"description": "POST /api/broadcasts/:id/send — 202 with the broadcast's new state: 'scheduled' when a future scheduledAt was given, else 'sending' (fan-out continues in the background; poll GET /api/broadcasts/:id for progress).",
"type": "object",
"required": [
"id",
"status",
"audienceCount"
],
"properties": {
"id": {
"type": "string",
"description": "The broadcast (bct_…).",
"examples": [
"bct_3Jf7HkPw"
]
},
"status": {
"type": "string",
"enum": [
"scheduled",
"sending"
],
"description": "State the broadcast moved to."
},
"scheduledAt": {
"type": "integer",
"description": "When a scheduled broadcast will send. Present only when status is 'scheduled', in Unix epoch milliseconds (UTC).",
"examples": [
1769731200000
]
},
"audienceCount": {
"type": "integer",
"description": "Audience size snapshotted at this moment.",
"examples": [
1284
]
}
}
}