Duplicate a campaign
POST/api/v1/email/campaigns/{id}/duplicate
POST /email/campaigns/{id}/duplicate
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 '{ }'Response · 201
{
"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"
}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.
Parameters2 fields
| Field | Type | Description |
|---|---|---|
idrequired | string · path | — |
Idempotency-Key | string · header | 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 body1 field
| Field | Type | Description |
|---|---|---|
name | string | Name of the copy. Defaults to the source's name with " (copy)". |
Response · 201 fields22 fields
| Field | Type | Description |
|---|---|---|
objectrequired | string | — |
idrequired | string | — |
namerequired | string | — |
template_idrequired | string | — |
segment_idrequired | string | — |
topic_idrequired | string | null | — |
fromrequired | string | — |
subjectrequired | string | null | — |
preview_textrequired | string | null | — |
open_trackingrequired | boolean | null | — |
click_trackingrequired | boolean | null | — |
statusrequired | enumdraft | scheduled | sending | paused | sent | canceled | failed | — |
scheduled_atrequired | string | null | — |
variable_fallbacksrequired | object | — |
excluded_contact_idsrequired | string[] | — |
total_recipientsrequired | number | 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 | 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_countrequired | number | — |
failed_countrequired | number | — |
pause_reasonrequired | object | null | — |
created_atrequired | string | — |
updated_atrequired | string | — |
201400401403404409422