# Campaigns API

> Create campaigns, choose their audiences, and send or schedule them.

Base URL: `https://api.emailit.com/v2`. Authenticate with `Authorization: Bearer <API key>`.

## Create a campaign — POST /campaigns

> Create a draft email campaign with its sender, subject and HTML or text body, ready to target audiences and send.

# Create a campaign

Creates a campaign in `draft` status. Requires an API key with the `full` scope. Emits a `campaign.created` event.

A new campaign has no recipients. Choose its audiences with [Update a campaign](/docs/api-reference/campaigns/update/), then [send or schedule it](/docs/api-reference/campaigns/send/). Credits are charged when the campaign sends: 2 credits per email.

`POST /campaigns`

## Body parameters

- `name` (string, required): Internal name of the campaign. Recipients don't see it. Other campaign endpoints accept the name in place of the ID, so keep names unique if you use them that way.

- `subject` (string): Subject line. Supports [merge tags](/docs/campaigns/merge-tags/) such as `{{first_name}}`.

- `from_email` (string): Sender address. It must be on a verified sending domain in the workspace, for example `news@acme.com`.

- `from_name` (string): Sender display name, for example `Acme`. The message is sent from `Acme <news@acme.com>`.

- `reply_to` (string): Reply-To address. Defaults to `from_email` when the campaign sends.

- `html` (string): HTML body that Emailit sends. Supports the merge tags `{{first_name}}`, `{{last_name}}`, `{{email}}`, `{{unsubscribe_url}}` and `{{cf.<key>}}` for custom fields. Set the body when you create the campaign.

- `text` (string): Plain-text body. Supports the same merge tags as `html`.

- `preview_text` (string): Preview text stored with the campaign. Emailit doesn't insert it into the message; add a hidden preheader to `html` if you need one.

- `content` (string): Editor source of the body (for example MJML), stored as-is. Emailit sends `html` and `text`, not `content`.

- `content_type` (string): Format of `content`: `html`, `text` or `mjml`. Emailit doesn't compile MJML; send the compiled HTML in `html`.

## Returns

Returns `201 Created` with the campaign object. `status` is `draft`. The response doesn't echo `html`, `text` or `content`.

Returns `400` if `name` is missing and `403` if the API key doesn't have the `full` scope.

**Request** `POST /campaigns`

**cURL**

```bash
curl -X POST https://api.emailit.com/v2/campaigns \
  -H "Authorization: Bearer $EMAILIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "October newsletter",
    "subject": "October news for {{first_name}}",
    "from_email": "news@acme.com",
    "from_name": "Acme",
    "reply_to": "support@acme.com",
    "html": "<p>Hi {{first_name}},</p><p>Here is what changed this month.</p><p><a href=\"{{unsubscribe_url}}\">Unsubscribe</a></p>",
    "text": "Hi {{first_name}}, here is what changed this month. Unsubscribe: {{unsubscribe_url}}"
  }'
```

**Node.js**

```javascript
const res = await fetch('https://api.emailit.com/v2/campaigns', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.EMAILIT_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    name: 'October newsletter',
    subject: 'October news for {{first_name}}',
    from_email: 'news@acme.com',
    from_name: 'Acme',
    reply_to: 'support@acme.com',
    html: '<p>Hi {{first_name}},</p><p>Here is what changed this month.</p><p><a href="{{unsubscribe_url}}">Unsubscribe</a></p>',
    text: 'Hi {{first_name}}, here is what changed this month. Unsubscribe: {{unsubscribe_url}}',
  }),
});
const campaign = await res.json();
```

**Python**

```python
import os, requests

r = requests.post(
    "https://api.emailit.com/v2/campaigns",
    headers={"Authorization": f"Bearer {os.environ['EMAILIT_API_KEY']}"},
    json={
        "name": "October newsletter",
        "subject": "October news for {{first_name}}",
        "from_email": "news@acme.com",
        "from_name": "Acme",
        "reply_to": "support@acme.com",
        "html": '<p>Hi {{first_name}},</p><p>Here is what changed this month.</p><p><a href="{{unsubscribe_url}}">Unsubscribe</a></p>',
        "text": "Hi {{first_name}}, here is what changed this month. Unsubscribe: {{unsubscribe_url}}",
    },
)
campaign = r.json()
```

**PHP**

```php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.emailit.com/v2/']);

$response = $client->post('campaigns', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('EMAILIT_API_KEY')],
    'json' => [
        'name' => 'October newsletter',
        'subject' => 'October news for {{first_name}}',
        'from_email' => 'news@acme.com',
        'from_name' => 'Acme',
        'reply_to' => 'support@acme.com',
        'html' => '<p>Hi {{first_name}},</p><p>Here is what changed this month.</p><p><a href="{{unsubscribe_url}}">Unsubscribe</a></p>',
        'text' => 'Hi {{first_name}}, here is what changed this month. Unsubscribe: {{unsubscribe_url}}',
    ],
]);
$campaign = json_decode($response->getBody(), true);
```

**201**

```json
{
  "object": "campaign",
  "id": "cmp_3zNrBaNjAoPK1l0IL2GQ3pDkubN",
  "name": "October newsletter",
  "status": "draft",
  "subject": "October news for {{first_name}}",
  "from_email": "news@acme.com",
  "from_name": "Acme",
  "reply_to": "support@acme.com",
  "preview_text": null,
  "content_type": "html",
  "created_at": "2026-10-01T09:30:12.482193Z",
  "updated_at": "2026-10-01T09:30:12.482193Z"
}
```

**400**

```json
{
  "error": "Bad Request"
}
```

**403**

```json
{
  "statusCode": 403,
  "error": "Forbidden",
  "message": "Permission denied: campaigns:create"
}
```

---
Source: https://emailit.com/docs/api-reference/campaigns/create/

## Retrieve a campaign — GET /campaigns/{id}

> Retrieve a campaign by ID or name, including its status, sender, schedule and the audiences it targets.

# Retrieve a campaign

Retrieves a campaign by its ID or name. Requires an API key with the `full` scope.

`GET /campaigns/{id}`

## Path parameters

- `id` (string, required): The campaign ID (`cmp_…`) or the campaign name. URL-encode names that contain spaces or special characters.

## Returns

Returns the campaign object.

- `object` (string): Always `campaign`.

- `id` (string): Campaign ID, prefixed `cmp_`.

- `status` (string): `draft`, `scheduled`, `queued`, `sending`, `sent`, `canceled` or `archived`. `queued` means a scheduled campaign has reached its send time and is waiting for a worker.

- `name` (string): Internal campaign name.

- `subject` (string): Subject line, with merge tags unresolved.

- `from_email` (string): Sender address. `""` until set.

- `from_name` (string): Sender display name. `""` until set.

- `reply_to` (string): Reply-To address. `""` means replies go to `from_email`.

- `preview_text` (string | null): Preview text stored with the campaign.

- `content_type` (string): Format label of the editor source: `html`, `text` or `mjml` for campaigns created through the API.

- `scheduled_at` (string | null): When a scheduled campaign sends, in UTC.

- `sent_at` (string | null): When sending started.

- `recipients` (object[]): Audiences the campaign targets. Each item has `audience_id` (`aud_…`) and `exclude` (`true` for an excluded audience).

The body (`html`, `text` and `content`) isn't included in the response. Engagement statistics are available in the dashboard under **Email Marketing → Campaigns**.

Returns `404` if no campaign in the workspace matches `id`.

**Request** `GET /campaigns/{id}`

**cURL**

```bash
curl https://api.emailit.com/v2/campaigns/cmp_3zNrBaNjAoPK1l0IL2GQ3pDkubN \
  -H "Authorization: Bearer $EMAILIT_API_KEY"
```

**Node.js**

```javascript
const res = await fetch('https://api.emailit.com/v2/campaigns/cmp_3zNrBaNjAoPK1l0IL2GQ3pDkubN', {
  headers: { Authorization: `Bearer ${process.env.EMAILIT_API_KEY}` },
});
const campaign = await res.json();
```

**Python**

```python
import os, requests

r = requests.get(
    "https://api.emailit.com/v2/campaigns/cmp_3zNrBaNjAoPK1l0IL2GQ3pDkubN",
    headers={"Authorization": f"Bearer {os.environ['EMAILIT_API_KEY']}"},
)
campaign = r.json()
```

**PHP**

```php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.emailit.com/v2/']);

$response = $client->get('campaigns/cmp_3zNrBaNjAoPK1l0IL2GQ3pDkubN', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('EMAILIT_API_KEY')],
]);
$campaign = json_decode($response->getBody(), true);
```

**200**

```json
{
  "object": "campaign",
  "id": "cmp_3zNrBaNjAoPK1l0IL2GQ3pDkubN",
  "name": "October newsletter",
  "status": "scheduled",
  "subject": "October news for {{first_name}}",
  "from_email": "news@acme.com",
  "from_name": "Acme",
  "reply_to": "support@acme.com",
  "preview_text": null,
  "content_type": "html",
  "sent_at": null,
  "scheduled_at": "2026-10-08 09:00:00+00",
  "created_at": "2026-10-01 09:30:12.482193+00",
  "updated_at": "2026-10-01 10:02:47.118204+00",
  "recipients": [
    { "audience_id": "aud_3Cz7WJ9GpvD7P0PQez50xOmkZSV", "exclude": false },
    { "audience_id": "aud_3hRmYTSQ4ca6y9tbPI0IQPjVTL9", "exclude": true }
  ]
}
```

**404**

```json
{
  "error": "Campaign not found"
}
```

---
Source: https://emailit.com/docs/api-reference/campaigns/get/

## Update a campaign — POST /campaigns/{id}

> Change a campaign's name, sender, subject or preview text, and set the audiences it sends to or excludes.

# Update a campaign

Updates the fields you pass and leaves the others unchanged. Use it to choose the campaign's audiences before you send it. Requires an API key with the `full` scope. Emits a `campaign.updated` event.

A scheduled campaign sends whatever is saved at its send time, so you can still edit it after scheduling.

`POST /campaigns/{id}`

## Path parameters

- `id` (string, required): The campaign ID (`cmp_…`) or the campaign name.

## Body parameters

- `name` (string): Internal campaign name.

- `subject` (string): Subject line. Supports [merge tags](/docs/campaigns/merge-tags/).

- `from_email` (string): Sender address on a verified sending domain.

- `from_name` (string): Sender display name.

- `reply_to` (string): Reply-To address. An empty string means replies go to `from_email`.

- `preview_text` (string): Preview text stored with the campaign.

- `content` (string): Editor source of the body, stored as-is.

- `content_type` (string): Format of `content`: `html`, `text` or `mjml`.

- `recipients` (object[]): The audiences to target. Replaces the current list. Include at least one audience with `exclude` set to `false`. - `audience_id` (string, required): an audience ID (`aud_…`) in this workspace. - `exclude` (boolean, default `false`): `true` saves the audience as an exclusion. The dashboard subtracts excluded audiences from its recipient estimate, but the send itself doesn't apply exclusions at the moment, so also remove those contacts from the included audiences. Duplicate audience IDs are ignored. At send time, Emailit emails every subscribed contact of the included audiences once, and skips unsubscribed contacts and suppressed addresses.

The HTML and text body are set when you [create the campaign](/docs/api-reference/campaigns/create/). Unknown body fields are ignored.

## Returns

Returns the updated campaign object, including `recipients`.

Returns `422` if `recipients` has no included audience or references an audience outside the workspace, and `404` if the campaign doesn't exist.

**Request** `POST /campaigns/{id}`

**cURL**

```bash
curl -X POST https://api.emailit.com/v2/campaigns/cmp_3zNrBaNjAoPK1l0IL2GQ3pDkubN \
  -H "Authorization: Bearer $EMAILIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "subject": "Your October update, {{first_name}}",
    "recipients": [
      { "audience_id": "aud_3Cz7WJ9GpvD7P0PQez50xOmkZSV" },
      { "audience_id": "aud_3hRmYTSQ4ca6y9tbPI0IQPjVTL9", "exclude": true }
    ]
  }'
```

**Node.js**

```javascript
const res = await fetch('https://api.emailit.com/v2/campaigns/cmp_3zNrBaNjAoPK1l0IL2GQ3pDkubN', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.EMAILIT_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    subject: 'Your October update, {{first_name}}',
    recipients: [
      { audience_id: 'aud_3Cz7WJ9GpvD7P0PQez50xOmkZSV' },
      { audience_id: 'aud_3hRmYTSQ4ca6y9tbPI0IQPjVTL9', exclude: true },
    ],
  }),
});
const campaign = await res.json();
```

**Python**

```python
import os, requests

r = requests.post(
    "https://api.emailit.com/v2/campaigns/cmp_3zNrBaNjAoPK1l0IL2GQ3pDkubN",
    headers={"Authorization": f"Bearer {os.environ['EMAILIT_API_KEY']}"},
    json={
        "subject": "Your October update, {{first_name}}",
        "recipients": [
            {"audience_id": "aud_3Cz7WJ9GpvD7P0PQez50xOmkZSV"},
            {"audience_id": "aud_3hRmYTSQ4ca6y9tbPI0IQPjVTL9", "exclude": True},
        ],
    },
)
campaign = r.json()
```

**PHP**

```php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.emailit.com/v2/']);

$response = $client->post('campaigns/cmp_3zNrBaNjAoPK1l0IL2GQ3pDkubN', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('EMAILIT_API_KEY')],
    'json' => [
        'subject' => 'Your October update, {{first_name}}',
        'recipients' => [
            ['audience_id' => 'aud_3Cz7WJ9GpvD7P0PQez50xOmkZSV'],
            ['audience_id' => 'aud_3hRmYTSQ4ca6y9tbPI0IQPjVTL9', 'exclude' => true],
        ],
    ],
]);
$campaign = json_decode($response->getBody(), true);
```

**200**

```json
{
  "object": "campaign",
  "id": "cmp_3zNrBaNjAoPK1l0IL2GQ3pDkubN",
  "name": "October newsletter",
  "status": "draft",
  "subject": "Your October update, {{first_name}}",
  "from_email": "news@acme.com",
  "from_name": "Acme",
  "reply_to": "support@acme.com",
  "preview_text": null,
  "content_type": "html",
  "scheduled_at": null,
  "created_at": "2026-10-01 09:30:12.482193+00",
  "updated_at": "2026-10-01 10:02:47.118204+00",
  "recipients": [
    { "audience_id": "aud_3Cz7WJ9GpvD7P0PQez50xOmkZSV", "exclude": false },
    { "audience_id": "aud_3hRmYTSQ4ca6y9tbPI0IQPjVTL9", "exclude": true }
  ]
}
```

**422**

```json
{
  "message": "Validation failed.",
  "errors": {
    "recipients": ["One or more audiences are invalid."]
  }
}
```

**404**

```json
{
  "error": "Campaign not found"
}
```

---
Source: https://emailit.com/docs/api-reference/campaigns/update/

## List campaigns — GET /campaigns

> List the campaigns in a workspace, newest first, with page-based pagination, search and filters by status, name and dates.

# List campaigns

Returns the workspace's campaigns, newest first. Requires an API key with the `full` scope.

`GET /campaigns`

## Query parameters

- `page` (integer): Page number, starting at 1.

- `limit` (integer): Campaigns per page, from 1 to 100.

- `search` (string): Case-insensitive match on the campaign name or subject.

- `status` (string): Shortcut status filter: `draft`, `scheduled`, `sending` (also matches `queued`), `sent`, `canceled`, `archived` or `all`.

- `match`, `order`, `direction`: see [Filtering](https://emailit.com/docs/api-reference/filtering/).

### Filter keys

Filters use `key.condition=value` query parameters, for example `status.exact=sent` or `created_at.after=2026-09-01`. See [Filtering](/docs/api-reference/filtering/) for the conditions per type.

| Key | Type | Notes |
| --- | --- | --- |
| `name` | string | |
| `subject` | string | |
| `status` | enum | `draft`, `scheduled`, `queued`, `sending`, `sent`, `archived` |
| `created_at` | date | |
| `sent_at` | date | |

Sort keys for `order`: `name`, `subject`, `status`, `created_at`, `sent_at`.

## Returns

Returns a page of campaign objects without `reply_to`, `preview_text`, `content_type` and `recipients`. Use [Retrieve a campaign](/docs/api-reference/campaigns/get/) for those.

- `data` (object[]): Campaigns on this page.

- `total_records` (integer): Number of campaigns that match the query.

- `next_page_url` (string | null): Path of the next page, or `null` on the last page. It carries only `page` and `limit`, so add your search and filters again when you follow it.

- `previous_page_url` (string | null): Path of the previous page, or `null` on the first page.

**Request** `GET /campaigns`

**cURL**

```bash
curl -G https://api.emailit.com/v2/campaigns \
  -H "Authorization: Bearer $EMAILIT_API_KEY" \
  -d limit=20 \
  -d status=sent \
  -d order=sent_at \
  -d direction=desc
```

**Node.js**

```javascript
const params = new URLSearchParams({ limit: '20', status: 'sent', order: 'sent_at', direction: 'desc' });
const res = await fetch(`https://api.emailit.com/v2/campaigns?${params}`, {
  headers: { Authorization: `Bearer ${process.env.EMAILIT_API_KEY}` },
});
const { data, total_records } = await res.json();
```

**Python**

```python
import os, requests

r = requests.get(
    "https://api.emailit.com/v2/campaigns",
    headers={"Authorization": f"Bearer {os.environ['EMAILIT_API_KEY']}"},
    params={"limit": 20, "status": "sent", "order": "sent_at", "direction": "desc"},
)
campaigns = r.json()["data"]
```

**PHP**

```php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.emailit.com/v2/']);

$response = $client->get('campaigns', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('EMAILIT_API_KEY')],
    'query' => ['limit' => 20, 'status' => 'sent', 'order' => 'sent_at', 'direction' => 'desc'],
]);
$campaigns = json_decode($response->getBody(), true)['data'];
```

**200**

```json
{
  "data": [
    {
      "object": "campaign",
      "id": "cmp_3zNrBaNjAoPK1l0IL2GQ3pDkubN",
      "name": "October newsletter",
      "status": "sent",
      "subject": "Your October update, {{first_name}}",
      "from_email": "news@acme.com",
      "from_name": "Acme",
      "sent_at": "2026-10-08 09:00:04+00",
      "scheduled_at": "2026-10-08 09:00:00+00",
      "created_at": "2026-10-01 09:30:12.482193+00",
      "updated_at": "2026-10-08 09:00:31+00"
    }
  ],
  "total_records": 34,
  "next_page_url": "/v2/campaigns?page=2&limit=20",
  "previous_page_url": null
}
```

---
Source: https://emailit.com/docs/api-reference/campaigns/list/

## Send or schedule a campaign — POST /campaigns/{id}/send

> Send a campaign to its audiences right away, or schedule a draft campaign for a future date and time.

# Send or schedule a campaign

Sends the campaign now, or schedules it when you pass a future `scheduled_at`. Requires an API key with the `full` scope and a [verified workspace](/docs/workspaces/production-access/): unverified workspaces can't send campaigns and get `403`.

Before you send, make sure the campaign has a `from_email` on a verified domain, a subject, an `html` or `text` body, and at least one included audience (set with [Update a campaign](/docs/api-reference/campaigns/update/)). Each email costs 2 credits.

`POST /campaigns/{id}/send`

## Path parameters

- `id` (string, required): The campaign ID (`cmp_…`) or the campaign name.

## Body parameters

- `scheduled_at` (string): When to send. Accepts ISO 8601 (`2026-10-08T09:00:00Z`), a Unix timestamp in seconds, or natural language such as `tomorrow at 9am` (interpreted in UTC). The time must be in the future and the campaign must be a `draft`. Omit it to send now. To send a scheduled campaign early, call this endpoint without `scheduled_at`.

## Returns

**Send now:** the status changes to `sending` and Emailit emits `campaign.sending`. Emailit then creates one email per recipient: every subscribed contact of the included audiences, deduplicated by address, without unsubscribed contacts and suppressed addresses. Once every recipient has been handed to the sending pipeline, the status changes to `sent` and Emailit emits `campaign.sent`. Track delivery in the dashboard or with [email events](/docs/webhooks/event-types/).

**Schedule:** the status changes to `scheduled` and Emailit emits `campaign.scheduled`. At the scheduled time the campaign becomes `queued` (`campaign.queued`) and then sends as above.

The response contains `object`, `id`, `name` and the new `status`, plus `scheduled_at` when you schedule.

| Status | When |
| --- | --- |
| `403` | The workspace isn't verified, or the API key doesn't have the `full` scope. |
| `404` | No campaign matches `id`. |
| `422` | `scheduled_at` can't be parsed or isn't in the future, or you tried to schedule a campaign that isn't a draft. |

**Request** `POST /campaigns/{id}/send`

**cURL**

```bash
curl -X POST https://api.emailit.com/v2/campaigns/cmp_3zNrBaNjAoPK1l0IL2GQ3pDkubN/send \
  -H "Authorization: Bearer $EMAILIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "scheduled_at": "2026-10-08T09:00:00Z" }'
```

**Node.js**

```javascript
const res = await fetch('https://api.emailit.com/v2/campaigns/cmp_3zNrBaNjAoPK1l0IL2GQ3pDkubN/send', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.EMAILIT_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ scheduled_at: '2026-10-08T09:00:00Z' }),
});
const campaign = await res.json();
```

**Python**

```python
import os, requests

r = requests.post(
    "https://api.emailit.com/v2/campaigns/cmp_3zNrBaNjAoPK1l0IL2GQ3pDkubN/send",
    headers={"Authorization": f"Bearer {os.environ['EMAILIT_API_KEY']}"},
    json={"scheduled_at": "2026-10-08T09:00:00Z"},
)
campaign = r.json()
```

**PHP**

```php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.emailit.com/v2/']);

$response = $client->post('campaigns/cmp_3zNrBaNjAoPK1l0IL2GQ3pDkubN/send', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('EMAILIT_API_KEY')],
    'json' => ['scheduled_at' => '2026-10-08T09:00:00Z'],
]);
$campaign = json_decode($response->getBody(), true);
```

**200 scheduled**

```json
{
  "object": "campaign",
  "id": "cmp_3zNrBaNjAoPK1l0IL2GQ3pDkubN",
  "name": "October newsletter",
  "status": "scheduled",
  "scheduled_at": "2026-10-08T09:00:00.000000Z"
}
```

**200 sending**

```json
{
  "object": "campaign",
  "id": "cmp_3zNrBaNjAoPK1l0IL2GQ3pDkubN",
  "name": "October newsletter",
  "status": "sending"
}
```

**403**

```json
{
  "code": "unverified_workspace_recipient",
  "error": "Workspace not verified",
  "message": "Unverified workspaces cannot send campaigns. You can send individual emails only to workspace members' account emails."
}
```

**422**

```json
{
  "error": "Campaign cannot be scheduled",
  "message": "Campaign status is 'sent'. Only draft campaigns can be scheduled."
}
```

---
Source: https://emailit.com/docs/api-reference/campaigns/send/

## Cancel a campaign — POST /campaigns/{id}/cancel

> Cancel a draft campaign or one that is sending. Emails that are already queued for delivery are not recalled.

# Cancel a campaign

Sets the campaign's status to `canceled` and emits a `campaign.canceled` event. Requires an API key with the `full` scope.

Only campaigns in `draft` or `sending` status can be canceled; any other status returns `422`. Canceling a campaign that is sending doesn't recall emails that are already queued for delivery.

`POST /campaigns/{id}/cancel`

## Path parameters

- `id` (string, required): The campaign ID (`cmp_…`) or the campaign name.

## Returns

Returns `object`, `id`, `name` and `status` (`canceled`).

Returns `422` if the campaign's status isn't `draft` or `sending`, and `404` if the campaign doesn't exist.

**Request** `POST /campaigns/{id}/cancel`

**cURL**

```bash
curl -X POST https://api.emailit.com/v2/campaigns/cmp_3zNrBaNjAoPK1l0IL2GQ3pDkubN/cancel \
  -H "Authorization: Bearer $EMAILIT_API_KEY"
```

**Node.js**

```javascript
const res = await fetch('https://api.emailit.com/v2/campaigns/cmp_3zNrBaNjAoPK1l0IL2GQ3pDkubN/cancel', {
  method: 'POST',
  headers: { Authorization: `Bearer ${process.env.EMAILIT_API_KEY}` },
});
const campaign = await res.json();
```

**Python**

```python
import os, requests

r = requests.post(
    "https://api.emailit.com/v2/campaigns/cmp_3zNrBaNjAoPK1l0IL2GQ3pDkubN/cancel",
    headers={"Authorization": f"Bearer {os.environ['EMAILIT_API_KEY']}"},
)
campaign = r.json()
```

**PHP**

```php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.emailit.com/v2/']);

$response = $client->post('campaigns/cmp_3zNrBaNjAoPK1l0IL2GQ3pDkubN/cancel', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('EMAILIT_API_KEY')],
]);
$campaign = json_decode($response->getBody(), true);
```

**200**

```json
{
  "object": "campaign",
  "id": "cmp_3zNrBaNjAoPK1l0IL2GQ3pDkubN",
  "name": "October newsletter",
  "status": "canceled"
}
```

**422**

```json
{
  "error": "Campaign cannot be canceled",
  "message": "Campaign status is 'scheduled'. Only 'draft' or 'sending' campaigns can be canceled."
}
```

**404**

```json
{
  "error": "Campaign not found"
}
```

---
Source: https://emailit.com/docs/api-reference/campaigns/cancel/

## Delete a campaign — DELETE /campaigns/{id}

> Permanently delete a campaign by ID or name. Emits a campaign.deleted event; emails already sent are not affected.

# Delete a campaign

Permanently deletes a campaign. Requires an API key with the `full` scope. Emits a `campaign.deleted` event.

Deleting a campaign doesn't affect emails that were already sent or queued. To stop a campaign that is sending, [cancel it](/docs/api-reference/campaigns/cancel/) first.

`DELETE /campaigns/{id}`

## Path parameters

- `id` (string, required): The campaign ID (`cmp_…`) or the campaign name.

## Returns

Returns `object`, `id`, `name` and `deleted: true`. Returns `404` if the campaign doesn't exist.

**Request** `DELETE /campaigns/{id}`

**cURL**

```bash
curl -X DELETE https://api.emailit.com/v2/campaigns/cmp_3zNrBaNjAoPK1l0IL2GQ3pDkubN \
  -H "Authorization: Bearer $EMAILIT_API_KEY"
```

**Node.js**

```javascript
const res = await fetch('https://api.emailit.com/v2/campaigns/cmp_3zNrBaNjAoPK1l0IL2GQ3pDkubN', {
  method: 'DELETE',
  headers: { Authorization: `Bearer ${process.env.EMAILIT_API_KEY}` },
});
const result = await res.json();
```

**Python**

```python
import os, requests

r = requests.delete(
    "https://api.emailit.com/v2/campaigns/cmp_3zNrBaNjAoPK1l0IL2GQ3pDkubN",
    headers={"Authorization": f"Bearer {os.environ['EMAILIT_API_KEY']}"},
)
result = r.json()
```

**PHP**

```php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.emailit.com/v2/']);

$response = $client->delete('campaigns/cmp_3zNrBaNjAoPK1l0IL2GQ3pDkubN', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('EMAILIT_API_KEY')],
]);
$result = json_decode($response->getBody(), true);
```

**200**

```json
{
  "object": "campaign",
  "id": "cmp_3zNrBaNjAoPK1l0IL2GQ3pDkubN",
  "name": "October newsletter",
  "deleted": true
}
```

**404**

```json
{
  "error": "Campaign not found"
}
```

---
Source: https://emailit.com/docs/api-reference/campaigns/delete/
