PUT /api/v2/buyer/campaigns/:campaignId
Accepts mode-specific campaign updates. For platform-managed campaigns, the
mediaBuys[] array lets you update, cancel, or delete individual media buys and
their packages in a single call. For a separately write-enrolled directed
campaign, the strict directed branch forwards one explicit AdCP patch to the
connected provider and reconciles the one-to-one mirror.
Request
Parameters
Directed update (alpha)
Read-only mirror refresh remains available without write enrollment:mediaBuy must contain at least one AdCP update field. The campaign URL resolves
the connected account and upstream identity, so nested account,
media_buy_id, idempotency_key, and revision fields are rejected. Use root
expectedRevision for optimistic concurrency. The root currency must match the
subscription governance currency.
A synchronous provider result returns { campaign, directedWrite } with
directedWrite.status: "CONFIRMED". If the provider accepted the write but the
mirror cannot yet prove it, the endpoint returns 202 Accepted with the raw
write result’s status AWAITING_CONFIRMATION; poll the campaign or use the
read-only refresh branch. Replaying the same idempotency key and body is safe. A
different body with the same key is a conflict and is never dispatched.
TikTok’s first write canary accepts only { "paused": true } or
{ "canceled": true, "cancellation_reason": "..." }. Resume, package
mutations, schedule/bid changes, and every other update fail closed. Its current
revision is not an authoritative compare-and-swap token, so Interchange does
not evaluate budget mutations against a potentially stale sibling-package
snapshot. TikTok has no native cancellation-reason field; Interchange retains
cancellation_reason as audit metadata alongside the directed write.
Reducing campaign budgets
Lower an executed campaign’s spend through this campaign update endpoint. Do not archive and rebuild a media buy just to reduce its budget. Every budget is gross (fee-inclusive), so the comparison is direct: live media buys can never allocate more thanbudget.total. Lowering
budget.total below what live media buys have already allocated is rejected
with INSUFFICIENT_MEDIA_BUDGET — the error names the new total and the
committed allocation so you know what to shrink or cancel first. Lowering into
headroom (new total at or above the current allocation) succeeds on its own.
To reduce the campaign and its live media buys together, put both changes in
one request: the new budget.total plus explicit
mediaBuys[].packages[].budget reductions. The request is validated against
the projected post-update allocation and applied atomically — if a package
reduction cannot be applied, the campaign-level budget.total is not lowered.
Lower into headroom — budget change alone
Reduce campaign budget and live packages in one call
Response
pacingPeriods, the response also carries a pacingCascadeResult block at the top level alongside campaign, summarizing the per-media-buy outcome of pushing appended periods to live media buys. See the Pacing periods guide for that shape, append-only rules, and unsupported-agent fallback.
When one or more media buy updates require seller approval (e.g. a seller-managed storefront), the server returns 202 Accepted with a proposals array instead of the campaign object:
Errors
400 VALIDATION_ERROR— acreative_idsentry is not linked to the campaign or does not match a format the media buy’s products accept (the field is not silently filtered); orcreative_idswas supplied withcancel/delete.403 FEATURE_NOT_ENABLED— a directed mutation was requested for a customer without the separate write alpha.409 CONFLICT— a directed idempotency key was reused for a different body orexpectedRevisionis stale.409 INSUFFICIENT_MEDIA_BUDGET— the requestedbudget.totalis below the projected live media buy allocation, even after applying the package budget reductions included in the same request. The error names the new total and the committed allocation.409 PRICING_NOT_CONFIGURED— the budget change involves media buys whose fee terms cannot be determined, so the projected allocation cannot be computed.details.unpricedBuyIdsnames the buys; resolve pricing for them first.404 NOT_FOUND— campaign or referencedmediaBuyIdnot found.
Related
Get campaign
Read the current resource first
Get media buy status
Poll live ADCP status
Pacing periods
Append-only pacing cascade
Campaign overview
Fields, lifecycle, and concepts