completed, working < 120s, or submitted for manual review)
Scope
update_media_buy operates on any media_buy_id returned by get_media_buys, not just buys created via create_media_buy. Sales agents MUST NOT refuse updates on the basis that a buy was originally created outside AdCP (direct ad-server entry, legacy APIs, manual trafficking). Creation surface is not a supported axis of authorization; account ownership is.
When a specific action is unsupported for a given buy for business reasons (contractual obligations, platform constraints, policy), the seller MUST omit only that action from valid_actions (and the corresponding entry from available_actions[]) on the buy rather than silently rejecting the corresponding update. Creation surface is not a business reason. Sellers MUST NOT return INVALID_STATE on an otherwise-valid update against a non-AdCP-created buy, and MUST NOT return a buy with systematically empty valid_actions simply because it was booked outside AdCP — that pattern is indistinguishable from hiding the buy and violates the Account Ownership vs. Creation Surface rule.
Action vocabulary and field mapping
Buyers express intent through actions; the seller declares the actions available on each buy via the structuredavailable_actions[] field (authoritative) and the flat valid_actions[] field (legacy, deprecated in 4.0). When both fields are present, consumers MUST prefer available_actions[] — it carries the resolved mode, optional sla, and optional terms_ref that the flat string array cannot represent. When a buyer issues an update_media_buy request, the seller maps the request’s fields to one or more actions and rejects with ACTION_NOT_ALLOWED (carrying attempted_action, reason, and currently_available_actions in error.details) if any mapped action is not in the buy’s resolved available_actions[].
The mapping is normative — sellers and SDKs MUST use this table to translate between request fields and action identifiers so the surface is consistent across implementations.
| Action | update_media_buy fields | Notes |
|---|---|---|
pause | paused: true | |
resume | paused: false | |
cancel | canceled: true, cancellation_reason | Irreversible |
extend_flight | end_time, packages[].end_time (later than current) | End-time push only |
shorten_flight | end_time, packages[].end_time (earlier than current) | End-time pull only |
update_flight_dates | start_time, end_time, packages[].start_time, packages[].end_time (shift) | Start-shift distinct from extend/shorten; covers both buy-level and package-level dates |
increase_budget | packages[].budget (raise) | |
decrease_budget | packages[].budget (lower) | Sellers typically bound by already-spent |
reallocate_budget | packages[].budget (redistribute, aggregate unchanged) |
extend_flight / shorten_flight, increase_budget / decrease_budget / reallocate_budget) share their update_fields paths; the action is determined by comparing the requested value against the buy’s current state, not by which field is set. Server-side dispatch enforcement MUST diff request-vs-current to pick the right action and reject with ACTION_NOT_ALLOWED if the resolved action is not in the buy’s available_actions[].
| update_targeting | packages[].targeting_overlay, packages[].keyword_targets_add, packages[].keyword_targets_remove, packages[].negative_keywords_add, packages[].negative_keywords_remove | |
| update_pacing | packages[].pacing | |
| update_frequency_caps | packages[].targeting_overlay.frequency_cap | Renegotiated mid-flight more often than other targeting. Field is singular frequency_cap (single rule), not plural. |
| replace_creative | packages[].creatives[] swap (assignments unchanged) | Distinct AM workflow from changing assignment set |
| update_creative_assignments | packages[].creative_assignments | Which creatives go where |
| remove_creative | Creative omitted from packages[].creatives[] and/or packages[].creative_assignments on a replacement payload | Both arrays use replacement semantics, so removal is expressed by sending the desired post-state with the creative absent (no explicit delete primitive in 3.x). Time-sensitive; sellers SHOULD support self_serve removal even when add/swap require approval |
| add_packages | new_packages[] | |
| remove_packages | packages[].canceled: true | |
The coarse legacy actions (update_budget, update_dates, update_packages, sync_creatives) cover the finer-grained vocabulary in a single value for sellers still emitting the 3.0 enum surface. Sellers SHOULD migrate to the finer set; the legacy values are removed in 4.0.
Action modes
Each entry inavailable_actions[] carries a singular mode (resolved against the buy’s current state). On the product-level allowed_actions[] template the field is modes[] (plural) because a product can offer multiple conditional modes (e.g. self_serve within tolerances, escalating to requires_approval outside).
| Mode | Meaning |
|---|---|
self_serve | Seller honors the request synchronously |
conditional_self_serve | Auto-approves within tolerances, escalates outside them (programmatic guaranteed pattern) |
requires_approval | Human-in-the-loop, async, no proposal artifact; buyer SDK polls or awaits webhook |
mode to decide whether to expect a synchronous response, conditional handling, or an asynchronous approval callback. Requotes are not modeled as an action mode in 3.1; sellers return REQUOTE_REQUIRED when a requested update exceeds the current quoted envelope.
PATCH Semantics: Only specified fields are updated; omitted fields remain unchanged.
Request Schema: /schemas/v3/media-buy/update-media-buy-request.json
Response Schema: /schemas/v3/media-buy/update-media-buy-response.json
Quick Start
Create a media buy, then pause it:Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
account | account-ref | Yes | Account that owns this media buy. Pass { "account_id": "..." } or { "brand": {...}, "operator": "..." }. Required for governance checks and account resolution. |
media_buy_id | string | Yes | Seller’s media buy identifier to update |
revision | integer | No | Expected current revision for optimistic concurrency. Seller rejects with CONFLICT on mismatch. Obtain from get_media_buys or the most recent response. |
start_time | string | No | Updated campaign start time |
end_time | string | No | Updated campaign end time |
paused | boolean | No | Pause/resume entire media buy (true = paused, false = active) |
canceled | boolean | No | Cancel the entire media buy (irreversible). Must be true when present. Seller may reject with NOT_CANCELLABLE. |
cancellation_reason | string | No | Reason for cancellation |
packages | PackageUpdate[] | No | Package-level updates (see below) |
reporting_webhook | object | No | Update reporting webhook configuration (see below) |
idempotency_key | string | No | Unique key for safe retries. If an update with the same key has already been processed, the seller returns the original response. MUST be unique per (seller, request) pair. Min 16 chars. |
invoice_recipient | BusinessEntity | No | Override who receives the invoice for this buy. The seller MUST validate authorization and include in check_governance when governance agents are configured. |
new_packages | PackageRequest[] | No | New packages to add to this media buy. Same shape as create_media_buy packages. Only supported by sellers that advertise add_packages in valid_actions. |
push_notification_config | object | No | Webhook for async operation notifications |
account and media_buy_id are always required.
Optimistic concurrency
revision is the expected current media-buy revision. Some implementations call this value expected_revision internally; on the AdCP wire the field is revision. The field is optional for backward compatibility. When it is present, sellers MUST check it atomically with the write that applies a mutating update; reading the current value in application code, comparing it, then writing later can race another writer and lose an update. If the stored revision differs from the request’s revision, the seller rejects with CONFLICT and applies no changes.
Every mutating update increments revision and returns the new value in the success response. Validation-only requests, reads, and exact idempotency replays do not increment it; exact replays return the prior revision. Clients SHOULD pass the latest observed revision on every update intended to change state, then reload with get_media_buys and retry with a fresh idempotency_key when they receive CONFLICT.
Reporting Webhook Object
Configure automated delivery reporting for this media buy:| Parameter | Type | Required | Description |
|---|---|---|---|
url | string | Yes | Webhook endpoint URL |
authentication | object | Yes | Auth config with schemes and credentials |
reporting_frequency | string | Yes | hourly, daily, or monthly |
requested_metrics | string[] | No | Specific metrics to include (defaults to all) |
token | string | No | Client token for validation (min 16 chars) |
reporting_webhook configures ongoing campaign reporting. push_notification_config is for async operation notifications (e.g., “notify me when this update completes”).
Package Update Object
| Parameter | Type | Description |
|---|---|---|
package_id | string | Seller’s package identifier to update |
paused | boolean | Pause/resume specific package (true = paused, false = active) |
canceled | boolean | Cancel this package (irreversible). Must be true when present. Seller may reject with NOT_CANCELLABLE. |
cancellation_reason | string | Reason for canceling this package |
budget | number | Updated budget allocation |
impressions | number | Updated impression goal for this package |
start_time | string | Updated flight start date/time in ISO 8601 format. Must fall within the media buy’s date range. |
end_time | string | Updated flight end date/time in ISO 8601 format. Must fall within the media buy’s date range. |
pacing | string | Updated pacing strategy |
bid_price | number | Updated bid price (auction products only). This is the exact bid/price to honor unless the selected pricing option has max_bid: true, in which case it is treated as the buyer’s maximum willingness to pay (ceiling). |
optimization_goals | OptimizationGoal[] | Replace all optimization goals for this package. Uses replacement semantics — omit to leave goals unchanged. |
targeting_overlay | TargetingOverlay | Updated targeting restrictions. Uses replacement semantics; changing signal_targeting_groups can alter priced signal selection, so sellers MAY reject with REQUOTE_REQUIRED when the selected signal, group expression, or signal pricing_option_id falls outside the original quote. Sellers SHOULD reject attempts to change fixed signal selections and MUST echo applied fixed/default signal groups on the resulting package state. |
catalogs | Catalog[] | Replace the catalogs this package promotes. Uses replacement semantics — omit to leave unchanged. |
keyword_targets_add | KeywordTarget[] | Keyword targets to add or upsert by (keyword, match_type) identity. On create, these are set as keyword_targets inside targeting_overlay. |
keyword_targets_remove | KeywordTarget[] | Keyword targets to remove by (keyword, match_type) identity. |
negative_keywords_add | NegativeKeyword[] | Negative keywords to append to this package. On create, these are set as negative_keywords inside targeting_overlay. |
negative_keywords_remove | NegativeKeyword[] | Negative keywords to remove from this package. |
creative_assignments | CreativeAssignment[] | Replace assigned creatives with optional weights and placement targeting |
creatives | CreativeAsset[] | Upload and assign new creatives inline (must not exist in library) |
package_id is required to identify the package to update.
Response
Success Response
| Field | Description |
|---|---|
media_buy_id | Media buy identifier |
media_buy_status | Media buy lifecycle status after the update (present when status changes, e.g., cancellation). Canonical 3.1 field. See Migration › media_buy_status. |
status | Deprecated in 3.1, removed in 3.2 (#4906). Use media_buy_status instead. Top-level status collides with the envelope task-status on flat-serialized MCP wire. |
revision | Revision number after this update. Use in subsequent requests intended to change state for optimistic concurrency. Exact idempotency replays return the prior revision. |
implementation_date | ISO 8601 timestamp when changes take effect (null if pending approval) |
invoice_recipient | Updated invoice recipient, echoed from request when provided. Confirms the seller accepted the billing override. Bank details are omitted (write-only). |
valid_actions | Flat-vocabulary actions the buyer can perform after this update. Saves a round-trip to get_media_buys. Deprecated in favor of available_actions[] and removed in 4.0. |
available_actions | Structured per-buy resolution of actions available after this update, each entry with action, resolved mode, optional sla, optional terms_ref. Authoritative — buyer SDKs SHOULD prefer this over valid_actions when both are present. |
affected_packages | Array of full Package objects showing complete state after update |
Error Response
| Field | Description |
|---|---|
errors | Array of error objects explaining failure |
errors before accessing success fields.
Common Scenarios
Update Package Budget
Increase budget for a specific package:Change Campaign Dates
Extend campaign end date:Update Targeting
Add or modify geographic restrictions:Replace Creatives
Swap out creative assignments for a package:Multiple Package Updates
Update multiple packages in one call:Cancel a Media Buy
Cancel an entire media buy:media_buy_status is the canonical 3.1 field for the buy’s lifecycle state. The legacy top-level status: MediaBuyStatus form (e.g., "status": "canceled") is deprecated and removed in 3.2 (#4906) — it collided with the envelope task-status at the same root key. See Migration › media_buy_status for the migration.
NOT_CANCELLABLE error response:
INVALID_STATE error response (e.g., trying to update a completed media buy):
REQUOTE_REQUIRED error response (update changes the parameter envelope the quote was priced against):
Cancel a Package
Cancel a single package while the media buy remains active:What Can Be Updated
Campaign-Level Updates
✅ Can update:- Start/end times (subject to seller approval)
- Campaign status (active/paused/canceled)
- Reporting webhook configuration (URL, frequency, metrics)
- Media buy ID
- Brand reference
- Original package product IDs
Package-Level Updates
✅ Can update:- Budget allocation
- Pacing strategy
- Bid prices (auction products)
- Optimization goal (event source, event type, target ROAS/CPA)
- Targeting overlays
- Creative assignments
- Package status (active/paused/canceled)
- Catalog reference (replace the catalog a catalog-driven package promotes)
- Creative assignments (before the package’s
creative_deadline)
not constraint on package-update.json):
- Package ID
- Product ID
- Pricing option ID
- Format selectors:
format_ids,format_option_refs,format_kind, andparams(creatives must match existing formats)
committed_metrics— sellers accept new entries (mid-flight metric additions, each with its owncommitted_attimestamp) but MUST reject attempts to modify or remove existing entries withvalidation_error(codeIMMUTABLE_FIELD). Runtime enforcement; the append-only semantics aren’t expressible in the schema’snotclause.
Error Handling
Common errors and resolutions:| Error Code | Description | Resolution |
|---|---|---|
MEDIA_BUY_NOT_FOUND | Media buy doesn’t exist | Verify media_buy_id; for legacy correlation use get_media_buys + context.internal_campaign_id |
PACKAGE_NOT_FOUND | Package doesn’t exist | Verify package_id; for legacy package correlation use get_media_buys + package context.buyer_ref |
UPDATE_NOT_ALLOWED | Field cannot be changed | See “What Can Be Updated” above |
BUDGET_INSUFFICIENT | New budget below minimum | Increase budget amount |
POLICY_VIOLATION | Update violates content policy | Review policy requirements |
INVALID_STATE | Operation not allowed in current state (e.g., updating completed/canceled media buy) | Check campaign status via get_media_buys |
NOT_CANCELLABLE | Media buy or package cannot be canceled | Check seller’s cancellation policy or contact seller |
CREATIVE_REJECTED | Creative failed content policy review | Revise the creative per the seller’s advertising policies |
CREATIVE_DEADLINE_EXCEEDED | Creative change submitted past the package’s creative_deadline | Check package creative_deadline before submitting creative changes |
CREATIVE_ID_EXISTS | Creative ID already exists in library | Use a different creative_id, assign existing creatives via creative_assignments, or update via sync_creatives |
BUDGET_EXCEEDED | Operation would exceed allocated budget | Reduce the amount or increase media buy total budget |
CONFLICT | Revision mismatch — another update was applied since you last read | Re-read via get_media_buys and retry with current revision |
REQUOTE_REQUIRED | Requested change (budget, dates, volume, targeting, or signal targeting price) falls outside the envelope the original quote was priced against | Adjust the update to fit the current quote, rediscover products/terms, add packages when add_packages is available, or create a separate media buy. 3.1 does not define an amendment-quote artifact for update_media_buy. Seller’s error.details.envelope_field names which fields breached. |
VALIDATION_ERROR | Request format or business rule violation | Check error field and message for specifics |
Update Approval
Some updates require seller approval and return pending status:- Significant budget increases (threshold varies by seller)
- Date range changes affecting inventory availability
- Targeting changes that alter campaign scope
- Creative changes requiring policy review
implementation_date will be null and affected_packages contains the proposed state of each package that would be modified:
PATCH Semantics
Only specified fields are updated - omitted fields remain unchanged:creative_assignments), provide the complete new array:
Asynchronous Operations
Updates may be asynchronous, especially with seller approval.Response Patterns
Synchronous (completed immediately) — campaign-level update (e.g.,paused: true):
Protocol-Specific Handling
AdCP tasks work across multiple protocols (MCP, A2A, REST). Each protocol handles async operations differently:- Status checking: Polling, webhooks, or streaming
- Updates: Protocol-specific mechanisms
- Long-running tasks: Different timeout and notification patterns
Best Practices
1. Use Precise Updates Update only what needs to change - don’t resend unchanged values. 2. Budget Increases Small incremental increases are more likely to be auto-approved than large jumps. 3. Pause Before Major Changes Pause campaigns before making significant targeting or creative changes to avoid delivery issues. 4. Test with Small Changes Test update workflows with minor changes before critical campaign modifications. 5. Monitor Status Always check response status andimplementation_date for approval requirements.
6. Validate Package State
Check affected_packages in response to confirm changes were applied correctly.
Usage Notes
- Updates are atomic - either all changes apply or none do
- Both media buys and packages can be referenced by publisher IDs
- Pending states (
working,submitted) are normal, not errors - Orchestrators MUST handle pending states as part of normal workflow
implementation_dateindicates when changes take effect (null if pending approval)- Inline creatives: The
creativesarray creates NEW creatives only. To update existing creatives, usesync_creatives. To assign existing library creatives, usecreative_assignmentsin the Package Update object.
Campaign Governance — Modification PhaseWhen a buyer’s account has governance agents configured, sellers MUST call
check_governance with media_buy_id, planned_delivery, and phase: "modification" before confirming an update. The governance agent validates change magnitude, budget reallocation, and new parameters against the campaign plan.See the seller integration guide for the full execution check workflow and code example.Next Steps
After updating a media buy:- Verify Changes: Use
get_media_buy_deliveryto confirm updates - Upload New Creatives: Use
sync_creativesif creative assignments changed - Monitor Performance: Track impact of changes on campaign metrics
- Optimize Further: Use
provide_performance_feedbackfor ongoing optimization
Learn More
- Media Buy Lifecycle - Complete campaign workflow
- Targeting - Targeting overlays and restrictions
- Async Operations - Async patterns and status checking
- create_media_buy - Initial campaign creation