Create a Campaign Plan
Creates a Campaign Plan. A Campaign Plan is the AdCrunch planning document. It is not a provider campaign. For provider campaigns, see the entities in the Observe API.
Only a name, a description and a currency are necessary. You write the window, the budget envelope and the Brand one part at a time. Write each amount in whole units of the currency: 40.5 is €40.50.
The new plan starts in draft. The answer is 409 if the slug already exists in your organization.
/context/campaign-plansAuthorizationBearer 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.
application/jsonbrand_namestringThe Brand's slug. Optional and re-pointable — a Campaign Plan may precede its brand or cover a portfolio. Addressed by slug because that is the handle every Context surface uses; the Campaign Plan stores the id.
currencystringrequiredISO 4217. Editable while no Line Item carries a budget, frozen thereafter.
descriptionstringrequiredOne-line summary — what a reader picks this Campaign Plan by.
end_datestringOmit for an always-on plan. Line Items inherit this.
measurementstringHow success will be judged (markdown).
namestringrequiredDisplay name.
rationalestringThe argument for the split — what a reviewer approves (markdown).
slugstringOptional explicit slug handle; normalized to kebab-case. Defaults to one derived from the name.
start_datestringtotal_budgetnumberThe envelope: what we have. Omit for "no declared constraint" — which is not the same as zero.
The Campaign Plan as created, in draft, at revision 1, with no rows. allocation.allocated is 0 and unallocated is the whole envelope.
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.
totaldailybrandIdstring | nullrequiredNullable and mutable: a plan may precede its brand, cover a portfolio, or be re-pointed. Deleting a Brand leaves its plans standing.
createdAtnumberrequiredMilliseconds since the Unix epoch, UTC.
createdBystringrequiredcurrencystringrequiredEditable until the first Line Item budget, and frozen thereafter.
descriptionstringrequiredendDatestring | nullrequiredA calendar date, YYYY-MM-DD.
idstringrequiredlineItemsobject[]requiredShow propertiesHide properties
objectadvertiserIdstring | nullrequiredageMaxnumber | nullrequiredageMinnumber | nullrequiredEach bound is independently optional, so "35+" is expressible.
budgetnumber | nullrequiredWhole units of the plan’s currency.
campaignPlanIdstringrequiredchannelstringrequiredThe planner’s word for what is being bought, not a provider name. A plan may name a channel we cannot execute.
metatiktoksnapchatgoogle_searchgoogle_pmaxgoogle_displayyoutubeprogrammatic_displaylinkedinxcountriesstring[]requiredcreatedAtnumberrequiredMilliseconds since the Unix epoch, UTC.
createdBystringrequiredeffectiveEndDatestring | nullrequiredThe line’s own bound where it has one, else the plan’s.
effectiveStartDatestring | nullrequiredA calendar date, YYYY-MM-DD.
endDatestring | nullrequiredA calendar date, YYYY-MM-DD.
executablebooleanrequiredWhether this channel could be executed at all today. Derived from our capabilities, never a promise that it will be.
executionsobject[]requiredWhat this line has spawned. Never a claim that it is finished — nobody declared how many objects a line should produce.
Show propertiesHide properties
objectadvertiserIdstringrequiredcreatedAtnumberrequiredMilliseconds since the Unix epoch, UTC.
entityIdstringrequiredThe provider’s own id, unprefixed, so it joins to entities.
entityTypestringrequiredThe provider’s word for the level — campaign, adset, ad.
idstringrequiredmutationWorkflowIdstring | nullrequiredThe durable execution that performed the write, when known.
providerstringrequiredgenderstring | nullrequiredallmenwomenidstringrequiredobjectivestringrequiredawarenessengagementleadssalestrafficapp_promotionpersonaIdstring | nullrequiredExplains the targeting; never supplies its values.
providerstring | nullrequiredWho sells this channel, or null when nobody we integrate with does.
revisionnumberrequiredIncrements on every write. Send it back as base_revision to edit; a stale one answers 409.
startDatestring | nullrequiredA calendar date, YYYY-MM-DD.
statusstringrequiredvalidated is the gate on execution.
draftvalidatedunitstringrequiredHow budget reads, derived from the effective end date. Present → a total for the period; absent → a daily rate. A surface must print this beside the amount.
totaldailyupdatedAtnumber | nullrequiredMilliseconds since the Unix epoch, UTC.
measurementstring | nullrequirednamestringrequiredrationalestring | nullrequiredrevisionnumberrequiredIncrements 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 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.
brand_name names no Brand in this organization. error is not_found. Despite its name the field takes a Brand slug.
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.
Another Campaign Plan already holds that slug. 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.
Four codes share this status. invalid_slug; invalid_currency (it must be a three-letter ISO 4217 code); invalid_amount (an amount has no more decimals than its currency, and is never negative); invalid_window (the end precedes the start).
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.