---
title: "Create a draft"
method: POST
path: "/api/v1/campaigns"
tags: ["Campaigns"]
---

# Create a draft

`POST /api/v1/campaigns`

## Request

- Base URL: `https://mailcheer.com`
- URL: `https://mailcheer.com/api/v1/campaigns`
- Auth: one of:
  - HTTP bearer
  - API key in header `X-Api-Key`

Permission required: `campaigns:write`. **Nothing goes out**: sending is a second action, deliberately kept separate.

Content is written either in blocks (`content`) or in plain text (`text`): a blank line separates two paragraphs, `# ` at the start of a line makes a heading.

## Request body

- CampaignRequest: The body of `POST /api/v1/campaigns`. Only `name` is required — but a draft with no subject and no content cannot be sent. Give the content through `text` (plain) or through `content` (blocks), never both.
  - `name` string, required: **Required.** Internal name, never seen by recipients.
  - `subject` string: The subject. It may stay empty on a draft, but the send will refuse it.
  - `preheader` string: Preview shown after the subject in the inbox.
  - `kind` string: Your own classification label. Free text, no imposed value.
  - `from` string: The address of a sender **already registered** in the workspace — not any address on a verified domain, unlike an individual send. Unknown: 404, with the list of available addresses. `GET /api/v1/me` gives them in `senders`.
  - `sender_id` string: The sender's identifier, if you know it (`senders[].id` from `GET /api/v1/me`). Takes precedence over `from`. With neither `from` nor `sender_id`, Mailcheer takes the workspace's default sender; failing that, if a single sender exists, that one. If several exist with no default, the campaign is created **without a sender** and it is the send that will fail: designate one.
  - `text` string: The content in plain text — the form to prefer from code or from an agent. A blank line separates two paragraphs, `# ` at the start of a line makes a heading, `## ` a subheading. Ignored if `content` is provided.
  - `content` object: The content in blocks, the editor's full form. Write this only if you are reusing the content of an existing campaign: to compose, `text` does the same job without your having to fabricate block identifiers.
    - `preheader` string
    - `blocks` object[]: Editor blocks, each with its `id` and its `type` (`heading`, `text`, …).

## Response `201`

Draft created.

- object
  - `id` string
  - `object` 'campaign'
  - `name` string
  - `status` 'draft'

## Other responses

- `401`: Key missing, unknown or revoked.
- `403`: The key does not have the requested permission, or the workspace cannot send: `sending_blocked` (suspended, blocked or banned — nothing goes out, through any channel), `commitment_required` (the anti-spam commitment is not accepted), `reputation_blocked` (too many bounces or complaints).
- `404`: The object does not exist in this workspace.
- `422`: Malformed field, unverified domain, or recipient on the suppression list.

---

[API](https://skmtc.dev/mailcheer/apis/mailcheer-api.md) · [All operations](https://skmtc.dev/mailcheer/apis/mailcheer-api/llms.txt) · [OpenAPI document](https://skmtc.dev/mailcheer/apis/mailcheer-api/revisions/ba64b7ef2170?raw)
