Create or edit a campaign

Overview

Create a campaign, or update one in progress, one step at a time: details (step 1), channels (step 2), schedule (step 3) and launch (step 4).

Use this to build a campaign the way the dashboard wizard does. Pass the step you're on; the required fields change by step.

You'll need the store_id and the fields for the step. Later steps need the campaign_id returned by the first.

Returns the campaign after each step. It stays a draft until step 4, which schedules it (status becomes scheduled). current_step records the furthest step reached; going back to an earlier step doesn't lower it.

Prerequisites

  • A bearer token. See Authentication.
  • The location's id (store_id). On steps 2–4, the campaign_id returned by step 1.
  • Before step 3, give the campaign a type: upload recipients (bulk_upload), define a file format (automation), or send type: "kiosk" on step 3.

Base URL

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

Endpoint

POST /api/v1/campaign/create

Authentication

Account token

  • store_id must be a location inside your own account; otherwise 422.
  • campaign_id must belong to the store_id you send; otherwise 404 Campaign not found.
  • A new campaign is created for the account of the user behind the token.

Rate limit

This endpoint has no rate limit.

Request parameters

None.

Request body

FieldTypeRequiredDescription
store_idintegerYesThe location the campaign belongs to. Must be inside your own account.
stepintegerYesThe wizard step: 1 details, 2 channels, 3 schedule, 4 launch. The other required fields depend on it.
campaign_idinteger or nullSteps 2–4On step 1, leave it out or send null to create a campaign, or send an id to edit one. Required on steps 2–4. Must be an existing campaign (otherwise 422) that belongs to store_id (otherwise 404).
namestringStep 1The campaign's name, up to 255 characters.
channel_smsbooleanStep 2true adds the SMS channel (or restores a removed one), false removes it. Send this, channel_email, or both. Only applied when the location's plan includes SMS review requests.
channel_emailbooleanStep 2true adds the email channel (or restores a removed one), false removes it. Send this, channel_sms, or both. Only applied when the location's plan includes email review requests.
per_day_requestintegerStep 3Most requests sent a day, 1–50. Returned as request_per_day.
request_frequencyintegerStep 3How often requests go out: 0 every day, 1 every other day, 2 once a week, 3 once every two weeks, 4 once a month.
delay_requestintegerStep 3Days to wait before the first request, 0–60. Returned as request_delay.
request_after_time_pststringNoStep 3. Time of day to send, in Pacific Time (H:i:s). Default 14:00:00. Returned as request_after_time_pst, and in UTC as request_after_time.
send_immediatelybooleanNoStep 3. true makes step 4 schedule the first send for now instead of after the delay. Default false.
typestring or nullStep 3Send it on step 3: bulk_upload, automation, kiosk or null, or leave it out. Only kiosk is applied (see below).
📘

Step 2 creates the channels without templates. Before you send or launch, attach one to each channel with POST /api/v1/campaign/template/email/update or /template/sms/update, using the channel's id from data.data.channels[].id in this response.

🚧

Only kiosk is applied at step 3. Step 3 writes type only when you send type: "kiosk", and then it sets or overwrites it, even on a campaign that was bulk_upload or automation. Any other value is ignored silently: the call returns 200 and the campaign keeps the type it already had. Set the other types before step 3: uploading recipients sets bulk_upload (see Upload recipients), and defining the file format with POST /api/v1/campaign/automate/file-headers sets automation. Step 3 returns 400 while the campaign has no type, or when it is automation without a file format.

Request payload

Step 1, a new campaign:

{
  "store_id": 3007,
  "step": 1,
  "campaign_id": null,
  "name": "Summer Review Campaign"
}

Step 2, channels:

{
  "store_id": 3007,
  "step": 2,
  "campaign_id": 4824,
  "channel_email": true,
  "channel_sms": true
}

Step 3, schedule:

{
  "store_id": 3007,
  "step": 3,
  "campaign_id": 4824,
  "per_day_request": 20,
  "request_frequency": 0,
  "delay_request": 0,
  "request_after_time_pst": "14:00:00",
  "send_immediately": false,
  "type": "kiosk"
}

Step 4, launch:

{
  "store_id": 3007,
  "step": 4,
  "campaign_id": 4824
}

Response body

The payload is inside data.

FieldTypeDescription
statusstringsuccess.
messagestringCampaign has been saved successfully.
campaign_idintegerThe campaign's id. Send it as campaign_id on the next step.
dataobjectThe campaign after the step.
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 has been saved successfully",
    "campaign_id": 4824,
    "data": {
      "id": 4824,
      "name": "Summer Review Campaign",
      "description": null,
      "status": "draft",
      "current_step": 1,
      "store_id": 3007,
      "scheduled_at": null,
      "started_at": null,
      "completed_at": null,
      "total_audience": null,
      "request_per_day": 50,
      "request_frequency": 0,
      "request_delay": 0,
      "request_after_time": "14:00",
      "next_execution_time": null,
      "request_file_status": "pending",
      "request_file_name": null,
      "send_immediately": false,
      "request_file_path": null,
      "type": null,
      "request_after_time_pst": "07:00:00",
      "request_file_url": null,
      "unique_code": "3r2mto",
      "channels": [],
      "email_requests": [],
      "sms_requests": [],
      "file_header": null
    }
  }
}

Examples

Success payload

Step 1, a new campaign: see Response payload. Later steps return the same shape, with channels filled after step 2 and status scheduled after step 4.

Error payload

400 Campaign already launched

Step 2 on a campaign that is no longer a draft.

{
  "message": "Bad Request",
  "status": "error",
  "errors": "Campaign is finalized and cannot be updated."
}

400 Review requests not on the plan

Step 2 when the location's plan has no enabled review-request feature.

{
  "message": "Bad Request",
  "status": "error",
  "errors": "Review solicitation is not enabled for this store. Please enable it in your plan or contact support for assistance."
}

400 No campaign type yet

Steps 3 and 4 while the campaign has no type, including step 3 with type left out.

{
  "message": "Bad Request",
  "status": "error",
  "errors": "Please upload the audience file first or setup automation first."
}

400 No file format

Steps 3 and 4 on an automation campaign without a file format.

{
  "message": "Bad Request",
  "status": "error",
  "errors": "Please setup automation first."
}

400 Recipient file not ready

Step 4 on a bulk_upload campaign. Other messages: Please upload the audience file first, File processing failed. Please upload the audience file again., No audience data found. Please upload the audience file first.

{
  "message": "Bad Request",
  "status": "error",
  "errors": "Please wait for the file to be processed"
}

404 Campaign not found

campaign_id belongs to a different location than store_id.

{
  "message": "Not Found",
  "status": "error",
  "errors": "Campaign not found"
}

422 Name missing

{
  "message": "The name field is required.",
  "errors": {
    "name": [
      "The name field is required."
    ]
  }
}

422 Location outside your account

{
  "message": "The selected store id does not belong to your company hierarchy.",
  "errors": {
    "store_id": [
      "The selected store id does not belong to your company hierarchy."
    ]
  }
}

422 Unknown campaign

{
  "message": "The selected campaign id is invalid.",
  "errors": {
    "campaign_id": [
      "The selected campaign id is invalid."
    ]
  }
}

422 Step 3 values out of range

{
  "message": "The per day request field must not be greater than 50. (and 2 more errors)",
  "errors": {
    "per_day_request": [
      "The per day request field must not be greater than 50."
    ],
    "request_frequency": [
      "The selected request frequency is invalid."
    ],
    "type": [
      "The selected type is invalid."
    ]
  }
}
StatusMeaning
200The step was saved; returns the campaign.
400The step can't be applied yet: the campaign is already launched, review requests aren't on the plan, or the campaign has no type, file format or processed recipient file.
401The token is missing, expired or invalid.
404campaign_id belongs to a different location than store_id.
422A field is invalid for the step, store_id is outside your account, or campaign_id doesn't exist.
500Unexpected server error.

Example request

curl --request POST \
  --url "https://production-api.shoutaboutus.com/api/v1/campaign/create" \
  --header 'Authorization: Bearer <bearer-token>' \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data '{"store_id": 3007, "step": 1, "campaign_id": null, "name": "Summer Review Campaign"}'

Did this page help you?