Duplicate a Campaign Plan
Duplicates a Campaign Plan: one new Campaign Plan, with a copy of each of its Line Items. Use it to run the same plan again, for example each month.
The copy keeps the name, the summary, the body, the currency, the envelope, the window and the Brand. Each Line Item keeps its name, channel, objective, countries, age range, gender, Persona, ad account, budget, window and target. The copy keeps the dates: edit them after the duplicate.
The copy does not keep the Executions, the Comments, the Assignees, the Favorites or the approval. The copy and each Line Item start in draft, at revision 1. A deleted Brand or a deleted Persona is not copied. The source does not change.
One write holds the copy and its Line Items. When it fails, no copy stays.
/context/campaign-plans/{slug}/duplicateAuthorizationBearer token · headerrequiredSend Authorization: Bearer <credential>.
Use an API key (acr_…), from the AdCrunch console under Settings → API keys.
The credential names the organization, and no operation takes an organization parameter.
See https://docs.adcrunch.dev/api/authentication.
slugstringrequiredapplication/jsonnamestringThe name of the copy. Omit for the name of the source followed by " (copy)", cut to 120 characters.
slugstringThe slug of the copy; normalized to kebab-case. Omit to derive it from the name: when that slug is taken, the copy takes -2, then -3, up to the first free one. A slug that you send and that is taken is 409.
The copy, in draft, at revision 1. lineItemCount counts the copied Line Items. List them with GET /campaign-plans/{slug}/line-items.
allocationobjectrequiredDerived on every read. Never stored.
Show propertiesHide properties
allocatednumber | nullrequiredThe sum of the Line Item budgets. null when the lines mix units, because that sum would be meaningless.
comparablebooleanrequiredFalse when the lines mix totals and daily rates. A surface must then print "not comparable" rather than a plausible-looking wrong total.
unallocatednumber | nullrequiredThe envelope less the allocated, where both are known.
unitstring | nullrequiredThe shared unit, when the lines agree on one.
totaldailyassigneesobject[]requiredThe current members who are accountable for the record, oldest first, at most 10. An Assignee grants no access. A member who left is not listed.
Show propertiesHide properties
objectidstringrequiredThe usr_… id of the member.
namestringrequiredThe name of the member.
bodystring | nullrequiredThe long document of the Campaign Plan, in markdown, or null when nobody wrote it. The list answers the description, never the body.
brandobject | nullrequiredThe name and the slug of the Brand, to show and link it. Null when the plan has no Brand, or when its Brand was deleted.
Show propertiesHide properties
namestringrequiredslugstringrequiredbrandIdstring | nullrequiredNullable and mutable: a plan may precede its brand, cover a portfolio, or be re-pointed. Deleting a Brand leaves its plans standing.
commentCountnumberrequiredThe number of live Comments on the plan, replies included. List them with GET /campaign-plans/{slug}/comments.
createdAtnumberrequiredMilliseconds since the Unix epoch, UTC.
createdBystringrequiredcurrencystringrequiredEditable until the first Line Item budget, and frozen thereafter.
descriptionstringrequiredendDatestring | nullrequiredA calendar date, YYYY-MM-DD.
idstringrequiredlineItemCountnumberrequiredThe number of live Line Items of the plan. List them with GET /campaign-plans/{slug}/line-items.
namestringrequiredrevisionnumberrequiredIncrements on every write. Send it back as base_revision to edit; a stale one answers 409.
slugstringrequiredstartDatestring | nullrequiredA calendar date, YYYY-MM-DD.
statusstringrequiredThe only two stored states. active, closed and "executed" are derived, never stored.
draftapprovedtotalBudgetnumber | nullrequiredupdatedAtnumber | nullrequiredMilliseconds since the Unix epoch, UTC.
The request does not match the schema of this operation: a field is missing or has the wrong type, or the body is not valid JSON. error is invalid_request, and issues names each field. Nothing was changed.
issuesobject[]requiredOne entry for each field that does not match.
Show propertiesHide properties
objectinstringrequiredThe part of the request that holds the field.
bodycookieheadersparamsquerymessagestringrequiredA sentence to show a person. Written to say what to do next. Reworded whenever it can be said better, so never branch on it.
pathstringrequiredA JSON Pointer into that part of the request, such as /filename. An empty string is the whole part.
errorstringrequiredA stable code for the failure. This is the field to branch on. It does not change for a given failure.
invalid_requestmessagestringrequiredA sentence to show a person. Written to say what to do next. Reworded whenever it can be said better, so never branch on it.
No API key, or one that does not resolve. See the security scheme. error is unauthorized.
errorstringrequiredA stable code for the failure. This is the field to branch on. It does not change for a given failure.
unauthorizedmessagestringrequiredA sentence to show a person. Written to say what to do next. Reworded whenever it can be said better, so never branch on it.
The organization has no active subscription. An owner subscribes at paywallUrl. error is organization_unentitled.
paywallUrlstring<uri>requiredThe page where an owner of the organization subscribes. Show it to the person.
errorstringrequiredA stable code for the failure. This is the field to branch on. It does not change for a given failure.
organization_unentitledmessagestringrequiredA sentence to show a person. Written to say what to do next. Reworded whenever it can be said better, so never branch on it.
The caller does not hold campaign_plan:write. error is forbidden.
errorstringrequiredA stable code for the failure. This is the field to branch on. It does not change for a given failure.
forbiddenmessagestringrequiredA sentence to show a person. Written to say what to do next. Reworded whenever it can be said better, so never branch on it.
No Campaign Plan with that slug. error is not_found.
errorstringrequiredA stable code for the failure. This is the field to branch on. It does not change for a given failure.
messagestringrequiredA sentence to show a person. Written to say what to do next. Reworded whenever it can be said better, so never branch on it.
The slug that you sent is taken. error is slug_conflict.
slugstringrequiredThe slug that is already taken.
errorstringrequiredA stable code for the failure. This is the field to branch on. It does not change for a given failure.
slug_conflictmessagestringrequiredA sentence to show a person. Written to say what to do next. Reworded whenever it can be said better, so never branch on it.
invalid_slug: the name or the slug holds no letter or digit.
errorstringrequiredA stable code for the failure. This is the field to branch on. It does not change for a given failure.
messagestringrequiredA sentence to show a person. Written to say what to do next. Reworded whenever it can be said better, so never branch on it.