---
title: "Duplicate a campaign"
description: "Copy a campaign into a new draft. `POST /api/v1/email/campaigns/{id}/duplicate`"
url: https://www.unitpost.com/docs/email/post-email-campaigns-id-duplicate
section: "Email API reference"
updated: 2026-10-13
---
# Duplicate a campaign

`POST /api/v1/email/campaigns/{id}/duplicate`

Copy a campaign into a new `draft`. Only configuration is copied (name, template, segment, sender, subject, preview text, topic, tracking overrides, fallbacks, exclusions), never the send time or status, and every create check runs again (template published, segment not archived, domain, limits). Optional `name` for the copy; any other key is a `422`. Pass an `Idempotency-Key` so a retry returns the same copy instead of making another. Requires the `campaigns:write` capability.

## Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | yes | — |
| `Idempotency-Key` | header | string | no | Any unique string (1–256 characters, e.g. a UUID). Retrying with the same key and the same body within 24 hours returns the first result instead of sending again; the same key with a different body is `409 invalid_idempotent_request`, and one still in flight is `409 concurrent_idempotent_requests`. |

## Request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | no | Name of the copy. Defaults to the source's name with " (copy)". |

## Response fields (201)

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `object` | string | yes | — |
| `id` | string | yes | — |
| `name` | string | yes | — |
| `template_id` | string | yes | — |
| `segment_id` | string | yes | — |
| `topic_id` | string \| null | yes | — |
| `from` | string | yes | — |
| `subject` | string \| null | yes | — |
| `preview_text` | string \| null | yes | — |
| `open_tracking` | boolean \| null | yes | — |
| `click_tracking` | boolean \| null | yes | — |
| `status` | enum | yes | One of: `draft`, `scheduled`, `sending`, `paused`, `sent`, `canceled`, `failed`. |
| `scheduled_at` | string \| null | yes | — |
| `variable_fallbacks` | object | yes | — |
| `excluded_contact_ids` | string[] | yes | — |
| `total_recipients` | number | yes | Recipients the engine admitted when the campaign started sending. 0 while it is `draft` or `scheduled`: read `projected_recipients`, or `sendable` from validate. |
| `projected_recipients` | object \| null | no | The audience counted when the campaign was sent or scheduled: `total` segment members, `reachable` who will get it, `skipped` (unsubscribed, suppressed, excluded). Null for a draft that was never sent: read validate. Read-only. |
| `sent_count` | number | yes | — |
| `failed_count` | number | yes | — |
| `pause_reason` | object \| null | yes | — |
| `created_at` | string | yes | — |
| `updated_at` | string | yes | — |

## Responses

| Status | Description |
| --- | --- |
| 201 | The new draft. |
| 400 | The body isn't JSON, or the `Idempotency-Key` header is not 1–256 characters. |
| 401 | Missing or invalid API key. |
| 403 | The sender's domain isn't added, is blocked, or isn't verified (`domain_not_found`, `domain_blocked`, `domain_not_verified`), or a plan limit (`limit_reached`). |
| 404 | Campaign not found. |
| 409 | Idempotency conflict (same key, different body or campaign, or still in flight), or the source's segment or topic is archived. |
| 422 | An unknown key, or a create check failed (e.g. the template isn't published). |

## Example request

```bash
curl -X POST 'https://www.unitpost.com/api/v1/email/campaigns/cmp_123/duplicate' \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'User-Agent: my-app/1.0' \
  -H 'Content-Type: application/json' \
  -d '{ }'
```

## Example response (201)

```json
{
  "object": "campaign",
  "id": "id_123",
  "name": "Example",
  "template_id": "template_123",
  "segment_id": "segment_123",
  "topic_id": "topic_123",
  "from": "you@yourdomain.com",
  "subject": "Welcome to Acme",
  "preview_text": "string",
  "open_tracking": false,
  "click_tracking": false,
  "status": "draft",
  "scheduled_at": "2026-01-01T00:00:00.000Z",
  "variable_fallbacks": {},
  "excluded_contact_ids": [
    "string"
  ],
  "total_recipients": 1,
  "projected_recipients": {
    "total": 1,
    "reachable": 0,
    "skipped": 0
  },
  "sent_count": 1,
  "failed_count": 1,
  "pause_reason": {
    "code": "user",
    "message": "string",
    "metric": "hard_bounce_rate",
    "value": 0,
    "threshold": 0,
    "sample": {
      "events": 0,
      "of": 0
    },
    "window": {
      "since": "string"
    },
    "decided_by": "floor",
    "resume": "self_serve",
    "paused_at": "2026-01-01T00:00:00.000Z"
  },
  "created_at": "2026-01-01T00:00:00.000Z",
  "updated_at": "2026-01-01T00:00:00.000Z"
}
```

## Links

- HTML reference (with Node.js, Python, Ruby, PHP, Laravel, Go, Java, Rust, .NET and CLI examples): https://www.unitpost.com/docs/email/post-email-campaigns-id-duplicate
- OpenAPI 3.1 (full schemas): https://www.unitpost.com/api/v1/openapi.json
