Duplicate a campaign

Overview

Copy a campaign as a new draft with the same channels and templates but no recipients or schedule.

Use this to reuse a campaign that worked.

You'll need the campaign_id.

Returns the new draft, named with "(Copy)". It starts again at step 1, with the daily limit, frequency and delay set to 0; set them again with step 3 of Create or edit a campaign.

Prerequisites

Base URL

EnvironmentURL
Productionhttps://production-api.shoutaboutus.com
Developmenthttps://development-api.shoutaboutus.com

Endpoint

POST /api/v1/campaign/{campaignId}/duplicate

Authentication

Account token

  • The campaign must belong to your own account. If it doesn't, the call returns 403 (You are not authorized to duplicate this campaign).

Rate limit

This endpoint has no rate limit.

Request parameters

ParameterInTypeRequiredDescription
campaignIdpathintegerYesThe id of the campaign to copy. Digits only.

Request body

None.

Request payload

None.

Response body

The payload is inside data.

FieldTypeDescription
statusstringsuccess.
messagestringCampaign duplicated successfully.
dataobjectThe new campaign, in the same shape as Get one campaign.
data.idintegerThe campaign's id. Use it as campaign_id in later calls.
data.namestringThe campaign's name.
data.descriptionstring or nullThe campaign's description, or null.
data.statusstringdraft, scheduled, in_progress, paused, completed or cancelled.
data.current_stepintegerThe furthest wizard step reached, 1 to 4. Going back to an earlier step doesn't lower it.
data.store_idintegerThe location the campaign belongs to.
data.scheduled_atstring or nullWhen the campaign was scheduled (step 4), or null.
data.started_atstring or nullWhen sending started, or null.
data.completed_atstring or nullWhen the campaign finished, or null.
data.total_audienceinteger or nullRecipient count stored on the campaign. null until recipients are added.
data.request_per_dayintegerMost requests sent a day. Set on step 3 as per_day_request.
data.request_frequencyintegerHow often requests go out: 0 every day, 1 every other day, 2 once a week, 3 once every two weeks, 4 once a month.
data.request_delayintegerDays to wait before the first request. Set on step 3 as delay_request.
data.request_after_timestringTime of day requests are sent, in UTC (H:i:s).
data.next_execution_timestring or nullWhen the next batch is due, or null until step 4.
data.request_file_statusstringStatus of the uploaded recipient file: pending, processing, completed or failed.
data.request_file_namestring or nullName of the uploaded recipient file, or null.
data.send_immediatelybooleantrue when step 4 schedules the first send for now.
data.request_file_pathstring or nullStorage path of the uploaded recipient file, or null.
data.typestring or nullbulk_upload, automation or kiosk; null until set.
data.request_after_time_pststring or nullThe same send time in Pacific Time (H:i:s), as sent in request_after_time_pst.
data.request_file_urlstring or nullURL of the uploaded recipient file, or null.
data.unique_codestringThe campaign's unique code. Use it as unique_code in Send a review request from a kiosk.
data.channelsarray of objectsThe campaign's email and SMS channels. Empty until step 2.
data.channels[].idintegerThe channel's id. Use it as channel_id when you attach a template.
data.channels[].rs_campaign_idintegerThe campaign the channel belongs to.
data.channels[].channel_typestringemail or sms.
data.channels[].is_enabledbooleanWhether the channel is on.
data.channels[].template_idinteger or nullThe attached email or SMS template, or null until you attach one.
data.channels[].follow_up_template_idinteger or nullThe follow-up email template, or null.
data.channels[].follow_up_intervalinteger or nullDays between the first email and its follow-up, or null.
data.channels[].follow_up_interval_countinteger or nullMost follow-ups sent, 1 to 3, or null.
data.channels[].unique_codestringThe channel's unique code. Use it with Remove a campaign's follow-up.
data.channels[].templateobject or nullThe attached email or SMS template, or null.
data.channels[].follow_up_email_templateobject or nullThe follow-up email template, or null.
data.email_requestsarray of objectsEmail review requests created for the campaign.
data.email_requests[].idintegerThe email request's id.
data.email_requests[].emailstringThe recipient's email address.
data.email_requests[].statusstringpending, sent or failed.
data.email_requests[].sent_atstring or nullWhen the email was sent.
data.email_requests[].delivered_atstring or nullWhen delivery was confirmed.
data.email_requests[].opened_atstring or nullWhen the email was first opened.
data.email_requests[].clicked_atstring or nullWhen a link was first clicked.
data.email_requests[].is_testbooleantrue for a test send.
data.email_requests[].unique_codestringThe request's unique code, used in its tracking links.
data.sms_requestsarray of objectsText review requests created for the campaign.
data.file_headerobject or nullThe file format of an automation campaign (see Get a campaign's file format), or null.

Response payload

{
  "data": {
    "status": "success",
    "message": "Campaign duplicated successfully",
    "data": {
      "id": 4826,
      "name": "Summer Review Campaign (Copy)",
      "description": null,
      "status": "draft",
      "current_step": 1,
      "store_id": 3007,
      "scheduled_at": null,
      "started_at": null,
      "completed_at": null,
      "total_audience": 0,
      "request_per_day": 0,
      "request_frequency": 0,
      "request_delay": 0,
      "request_after_time": "21:00:00",
      "next_execution_time": null,
      "request_file_status": "pending",
      "request_file_name": null,
      "send_immediately": false,
      "request_file_path": null,
      "type": "kiosk",
      "request_after_time_pst": "14:00:00",
      "request_file_url": null,
      "unique_code": "a1b2c3",
      "channels": [
        {
          "id": 5396,
          "rs_campaign_id": 4826,
          "channel_type": "email",
          "is_enabled": true,
          "template_id": 9083,
          "follow_up_template_id": null,
          "follow_up_interval": null,
          "follow_up_interval_count": null,
          "unique_code": "d4e5f6",
          "template": {
            "id": 9083,
            "company_id": 5994,
            "store_id": 3007,
            "name": "Default Email Template",
            "subject": "How did we do?",
            "html_content": "<p>Hi [customerName], tell us how we did.</p>",
            "json_content": [],
            "template_editor_mode": "custom",
            "template_type": "regular",
            "manager_email": null,
            "other_manager_email": [],
            "created_at": "2026-09-23T10:43:44.000000Z",
            "updated_at": "2026-10-01T08:02:34.000000Z",
            "deleted_at": null
          },
          "follow_up_email_template": null
        }
      ],
      "email_requests": [],
      "sms_requests": [],
      "file_header": null
    }
  }
}

Examples

Success payload

See Response payload.

Error payload

403 Campaign outside your account

{
  "message": "Forbidden",
  "status": "error",
  "errors": "You are not authorized to duplicate this campaign"
}

422 Unknown campaign

{
  "message": "The selected id is invalid.",
  "errors": {
    "id": [
      "The selected id is invalid."
    ]
  }
}
StatusMeaning
200The new draft campaign.
401The token is missing, expired or invalid.
403The campaign belongs to another account.
422No campaign has that id.
500Unexpected server error.

Example request

curl --request POST \
  --url "https://production-api.shoutaboutus.com/api/v1/campaign/4823/duplicate" \
  --header 'Authorization: Bearer <bearer-token>' \
  --header 'Accept: application/json'

Did this page help you?