DRAFT. The draft is your cart: you add proposals and products to it and
stage media buys against it without contacting any seller. Launching turns the staged buys into real
AdCP transactions, one per seller.
Key fields
string
required
Stable id with the
cmp_ prefix.integer
required
The advertiser that owns the campaign. The budget currency must match the advertiser’s primary
currency.
string
required
Display name, 1 to 200 characters.
string
The plain-language description sellers read: goals, audience, channels, must-haves and
constraints. Up to 20,000 characters. The better the brief, the better the proposals.
enum
managed for campaigns authored in Semicola, which places and runs their buys. Every campaign
you create today is managed. The value tracked is reserved for campaigns mirrored read-only
from a connected ad platform account; mirroring isn’t available yet, so no campaign is
tracked and the campaign list’s Tracking lens stays empty.object
startAt and endAt, both ISO 8601 date-times with an offset.object
total (decimal), currency (ISO 4217), pacing (EVEN, ASAP or FRONTLOADED) and an
optional dailyCap. Every package staged on the campaign is sent to its seller with the
matching pacing (even, asap or front_loaded); change a single package’s pacing with
update_media_buy.decimal string
How much of the total is committed to staged or live media buys, and how much is left. Allocated
budget can never exceed the total.
object
Structured intent sent with the brief:
countries, channels, ageRange (min 13 or more,
max 99 or less), audience (free text) and geoMetros. Sellers that cannot honor part of it
say so in their proposal.object
How independently Semi works on the campaign:
inventorySelection and rebriefing, each manual,
propose or automatic. Without a value, a new campaign copies its advertiser’s setting. With
inventorySelection: "automatic", manual staging is refused and products come from
auto-select. The campaign workspace shows it under
Controls as Inventory selection and Re-briefing, marked when it differs from the advertiser.
See Autonomy and auto-select.object
Holds
optimizationGoals: the ranked goals sellers optimize toward, primary first, 1 to 10. Set
them with save_campaign (optimizationGoals) or REST performanceConfig. See
Optimization goals.array
Coherent inventory selections (for example mobile web display and CTV). Each group becomes its own
media buy per seller, and delivery can be reported by group. See Channel groups.
array
Buyer-side caps (
max_impressions per window). Stored, never sent to sellers and not enforced; see
Frequency caps.object
Values from your account’s dimensions, such as
{ "market": ["us"], "tags": ["launch"] }. Set with
save_campaign; filter campaigns by them. See Dimensions and labels.object
Format coverage for launch:
required, covered and missing.array
The campaign’s media buys, one per seller (and settlement currency). See media buys and
packages.
integer
required
Increments on every change. Writes that modify a campaign send
expectedRevision; a stale value
fails with REVISION_CONFLICT so two agents never overwrite each other.Optimization goals
A goal tells each seller what to optimize the campaign’s packages toward. Goals are opt-in: set them when the buyer states one. There are two kinds. Event goals (kind: "event") optimize toward conversions from the advertiser’s
event sources:
Metric goals (
kind: "metric") optimize toward a delivery metric the seller tracks: metric is
one of clicks, views, completed_views, viewed_seconds, attention_seconds,
attention_score, engagements, follows, saves, profile_visits or reach, with optional
viewDurationSeconds, a target (cost_per or threshold_rate, each with a value),
attributionWindow and priority. A campaign’s reach goal takes no reachUnit: sellers need one,
so each package is sent the first reach unit its product declares, and a package whose product
declares none is sent without the reach goal.
- Set.
save_campaigntakesoptimizationGoalson create and on update. Over REST, sendperformanceConfig: { "optimizationGoals": [ … ] }onPOST /campaigns,PUT /campaigns/{id}orcampaign.createin the media-buy batch (POST /media-buys/batch). - Change. A list replaces the whole ranked list; omitting the field keeps the current goals;
nullclears them (REST:performanceConfig: null). An empty list is refused. A change is recorded in the campaign’s activity as Optimization goals. - Validation. Every
eventSourceIdmust be a registered source of the campaign’s advertiser. Otherwise the write fails withVALIDATION_ERRORonoptimizationGoals, naming the missing keys indetails.unknownEventSourceIds. Register sources first (see Event sources). EacheventTypemust be one the source sends (itseventTypes). Otherwise the write fails the same way, and each mismatch is listed indetails.unsupportedEventTypeswitheventSourceId,eventTypeand the source’ssourceEventTypes. - Sent. When a buy goes to its seller, every package carries the ranked goals as AdCP
optimization_goals. Each event source is replaced by the seller’s own id for it; an event goal whose source isn’tprovisionedon that seller, or whose seller has Events turned off in Connections, is left out of that buy, and the buy goes ahead. See How a source reaches each seller. - Live buys. Changing the goals on a live campaign sends the new ranked list to each of its
ACTIVEandPAUSEDbuys withupdate_media_buy(packages[].optimization_goals;nullsends an empty list). The response carriesoptimizationGoalsCascadeResult:totalMediaBuys,updatedCount,pendingCount,skippedCount,failedCountand oneresultsentry per buy (outcomeupdated,pending,skippedorfailed, with areason).pendingmeans the seller must approve first; poll itsupdateProposalIdwithget_update_proposal. A buy is skipped when Buy is off for its seller, when a change is already waiting for that seller’s approval, or when it has no seller-side buy. Draft buys pick up the goals when they’re sent.
performanceConfig).
Lifecycle
PAUSED.
Launch preconditions
A draft can launch when all of these hold:- the advertiser is active and the budget currency matches its primary currency;
- at least one media buy is staged;
- allocated budget does not exceed the total;
- the required creative formats are covered, or you accept that some buys will wait for creatives;
- the account is allowed to buy live (otherwise only sandbox launches are possible).
open_campaign_receipt) shows each of these as a checklist with any
blockers.
Common operations
Create a draft
needs_input and a
question instead of guessing. Ask the person, then call again.
Collect proposals and stage buys
request_proposalswithcampaignIdandexpectedCampaignRevisionsends the brief to every eligible seller and returns an execution id straight away. Only one execution runs per buyer at a time.- Poll with
get(kind: "proposal") or watch the Proposals widget as sellers answer. refine_proposalasks one seller for a revised version.save_media_buywithfromProposalIdstages the proposal’s products as a draft media buy.
Launch
Launching is deliberately two calls so a person can see the spend before it happens.1
Ask to go live
Call
save_campaign with campaignId, expectedRevision and desiredPhase: "active". The
result is pending_confirmation, with a summary of spend per seller and an expiry.2
Get the person's approval
Show the summary. In the Semicola app and in MCP Apps hosts, a confirmation card does this for
you.
3
Confirm
Call
save_campaign again with confirmLaunch: true and the same expectedRevision. Semicola
dispatches one AdCP create_media_buy per seller, each with its own idempotency key.mediaBuysExecuted and a list of errors, one per failed buy, with a
recovery of transient, correctable or terminal and a retrySafe flag. Launching again
resubmits only the failed draft buys.
Pause, reactivate, cancel, archive
SendisPaused, desiredPhase: "canceled" or isArchived to save_campaign with
expectedRevision. Over REST, use POST /api/v2/buyer/campaigns/{id}/pause and
/reactivate.
Media buys and packages
A media buy is one AdCP transaction with one seller in one settlement currency. Its id starts withmb_. A package (pkg_) is one product inside a media buy, with its own budget, pacing
(even, asap or front_loaded), optional bid price, flight and creatives.
The campaign’s operational status is the most restrictive status across its buys: one of
no_media_buys, draft, pending_creatives, pending_start, active, paused, completed or
attention_required. Read it from GET /api/v2/buyer/campaigns/{id}/media-buy-status or the campaign
workspace.
Related
Buying overview
The whole loop from brief to delivery.
v3 Tool Catalog
Exact inputs for
save_campaign, request_proposals and save_media_buy.Errors
Revision conflicts,
needs_input and partial launches.Glossary
Every term on this page, defined.