{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/media-buy/update-media-buy-request.json",
  "title": "Update Media Buy Request",
  "description": "Deprecated AdCP 3.x compatibility request for campaign, package, and creative mutation. New 3.2 callers use control_media_buy for operational controls, refine_proposals for commercial amendments or negotiated cancellation, and the dedicated creative lifecycle for creative changes.",
  "type": "object",
  "deprecated": true,
  "x-deprecated-in": "3.2.0",
  "x-superseded-by": [
    "control_media_buy",
    "refine_proposals"
  ],
  "allOf": [
    {
      "$ref": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/core/version-envelope.json"
    },
    {
      "if": {
        "properties": {
          "bidding": {
            "type": "object"
          }
        },
        "required": [
          "bidding"
        ]
      },
      "then": {
        "properties": {
          "packages": {
            "items": {
              "not": {
                "anyOf": [
                  {
                    "required": [
                      "bid_price"
                    ]
                  },
                  {
                    "properties": {
                      "optimization_goals": {
                        "contains": {
                          "properties": {
                            "target": {
                              "properties": {
                                "kind": {
                                  "enum": [
                                    "cost_per",
                                    "per_ad_spend"
                                  ]
                                }
                              },
                              "required": [
                                "kind"
                              ]
                            }
                          },
                          "required": [
                            "target"
                          ]
                        }
                      }
                    },
                    "required": [
                      "optimization_goals"
                    ]
                  }
                ]
              }
            }
          },
          "new_packages": {
            "items": {
              "not": {
                "anyOf": [
                  {
                    "required": [
                      "bid_price"
                    ]
                  },
                  {
                    "properties": {
                      "optimization_goals": {
                        "contains": {
                          "properties": {
                            "target": {
                              "properties": {
                                "kind": {
                                  "enum": [
                                    "cost_per",
                                    "per_ad_spend"
                                  ]
                                }
                              },
                              "required": [
                                "kind"
                              ]
                            }
                          },
                          "required": [
                            "target"
                          ]
                        }
                      }
                    },
                    "required": [
                      "optimization_goals"
                    ]
                  }
                ]
              }
            }
          }
        }
      }
    },
    {
      "if": {
        "required": [
          "new_packages"
        ],
        "not": {
          "properties": {
            "budget_allocation": {
              "properties": {
                "mode": {
                  "const": "seller_optimized"
                }
              },
              "required": [
                "mode"
              ]
            }
          },
          "required": [
            "budget_allocation"
          ]
        }
      },
      "then": {
        "properties": {
          "new_packages": {
            "items": {
              "required": [
                "budget"
              ],
              "not": {
                "required": [
                  "min_spend_target"
                ]
              }
            }
          }
        }
      }
    }
  ],
  "x-mutates-state": true,
  "x-governed-commitment": {
    "scope": "conditional",
    "triggers": [
      "increases_obligation",
      "extends_term",
      "resumes_execution",
      "reallocates_delivery"
    ],
    "exemptions": [
      "cancel",
      "pause",
      "decrease_only"
    ],
    "precedence": "trigger_overrides_exemption"
  },
  "properties": {
    "governance_context": {
      "type": "string",
      "description": "Opaque intent authorization for a commitment-increasing media-buy update.",
      "minLength": 1,
      "maxLength": 4096,
      "pattern": "^[\\x20-\\x7E]+$"
    },
    "account": {
      "$ref": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/core/account-ref.json",
      "description": "Account that owns this media buy. Pass a natural key (brand, operator, optional sandbox) or a seller-assigned account_id from list_accounts. Required for governance checks and account resolution."
    },
    "media_buy_id": {
      "type": "string",
      "description": "Seller's ID of the media buy to update",
      "x-entity": "media_buy"
    },
    "name": {
      "type": "string",
      "minLength": 1,
      "maxLength": 255,
      "pattern": "\\S",
      "description": "Replacement human-readable name for this media buy, used for trafficking UI display and operational communication. Sellers that cannot update name mid-flight SHOULD echo the prior unchanged value in the success response rather than silently dropping the field. This display label is not an identifier or financial reference."
    },
    "revision": {
      "type": "integer",
      "description": "Expected current revision for optimistic concurrency. Optional for backward compatibility. When provided, sellers MUST reject the update with CONFLICT if the media buy's current revision does not match, and MUST enforce that comparison atomically with the write. Obtain from get_media_buys or the most recent create/update response.",
      "minimum": 1
    },
    "paused": {
      "type": "boolean",
      "description": "Pause/resume the entire media buy (true = paused, false = active)"
    },
    "canceled": {
      "type": "boolean",
      "description": "Cancel the entire media buy. Cancellation is irreversible — canceled media buys cannot be reactivated. Sellers MAY reject with NOT_CANCELLABLE if the media buy cannot be canceled in its current state.",
      "const": true
    },
    "cancellation_reason": {
      "type": "string",
      "description": "Reason for cancellation. Sellers SHOULD store this and return it in subsequent get_media_buys responses.",
      "maxLength": 500
    },
    "start_time": {
      "$ref": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/core/start-timing.json"
    },
    "end_time": {
      "type": "string",
      "format": "date-time",
      "description": "New end date/time in ISO 8601 format"
    },
    "total_budget": {
      "type": "object",
      "description": "Updated hard aggregate lifetime budget. currency MUST equal the existing media-buy currency; an update does not redenominate a buy. When supplied alone (without packages or new_packages), in fixed mode the seller MUST atomically scale every active package budget in proportion to its current committed budget, rejecting the entire request if any derived budget cannot be accepted. When supplied with packages or new_packages, the amount MUST equal the resulting fixed-mode package sum; the seller applies the explicit package mutations and rejects with VALIDATION_ERROR if the total is inconsistent. In seller-optimized mode this changes the shared pool without converting package caps into allocations. Already-spent amounts still count against the new total.",
      "properties": {
        "amount": {
          "type": "number",
          "minimum": 0
        },
        "currency": {
          "type": "string",
          "pattern": "^[A-Z]{3}$"
        }
      },
      "required": [
        "amount",
        "currency"
      ],
      "additionalProperties": false
    },
    "daily_budget_cap": {
      "type": [
        "number",
        "null"
      ],
      "minimum": 0,
      "description": "Replace the hard aggregate daily cap; null removes it. Numeric changes apply immediately with current-day spend counted. A cap below that spend pauses delivery for the day. Package caps are unchanged. Requires advertised media_buy scope; otherwise rejected with UNSUPPORTED_FEATURE."
    },
    "budget_cap_timezone": {
      "type": [
        "string",
        "null"
      ],
      "minLength": 1,
      "description": "Replace the shared IANA cap-day timezone; null restores the default selected by budget_capping.timezone_basis (Account.timezone or fixed_timezone). Requires buyer_timezone_override. Changes start at the next boundary in the previously effective timezone; numeric cap changes remain immediate."
    },
    "budget_allocation": {
      "allOf": [
        {
          "$ref": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/core/budget-allocation.json"
        }
      ],
      "description": "Updated allocation configuration. Switching between fixed and seller-optimized modes is allowed only when update_budget_allocation is advertised in available_actions and the resulting package constraints are valid."
    },
    "pacing": {
      "$ref": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/enums/pacing.json",
      "description": "Updated aggregate media-buy pacing. Package pacing remains subordinate to this aggregate strategy."
    },
    "bidding": {
      "description": "Replace the complete media-buy-authored bidding default. An object replaces the prior block; `{automatic:true}` records an explicit automatic policy. null clears it; packages with explicit package.bidding remain explicit, while packages without overrides fall back to provider automatic delivery. Goal binding follows the resulting budget allocation: seller-optimized outcome controls bind to allocation goals, while fixed inherited cost_per requires compatible package result units. Monetary fields use the media-buy currency and all affected pricing options MUST match it. The seller MUST validate all resulting policies atomically before mutation.",
      "anyOf": [
        {
          "$ref": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/core/bidding-policy.json"
        },
        {
          "type": "null"
        }
      ]
    },
    "packages": {
      "type": "array",
      "description": "Package-specific updates for existing packages",
      "items": {
        "$ref": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/media-buy/package-update.json"
      },
      "minItems": 1
    },
    "invoice_recipient": {
      "$ref": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/core/business-entity.json",
      "description": "Update who receives the invoice for this buy. When provided, the seller invoices this entity instead of the account's default billing_entity. The seller MUST validate the invoice recipient is authorized for this account. When governance_agents are configured, the seller MUST include invoice_recipient in the check_governance request."
    },
    "new_packages": {
      "type": "array",
      "description": "New packages to add to this media buy. Uses the same schema as create_media_buy packages. When budget_allocation is omitted or fixed, every new package MUST carry budget and MUST NOT carry min_spend_target. To add a package without a hard cap to an existing seller-optimized buy, include its resulting seller_optimized budget_allocation block in the update so the allocation context is schema-visible. Repeating an unchanged allocation block does not itself switch modes. Sellers that support mid-flight package additions advertise `add_packages` in both `valid_actions[]` (deprecated) and as an entry in `available_actions[]` (authoritative). Sellers that do not support this MUST reject with ACTION_NOT_ALLOWED (preferred) or UNSUPPORTED_FEATURE (legacy).",
      "items": {
        "$ref": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/media-buy/package-request.json"
      },
      "minItems": 1
    },
    "reporting_webhook": {
      "$ref": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/core/reporting-webhook.json",
      "description": "Optional webhook configuration for automated reporting delivery. Updates the reporting configuration for this media buy."
    },
    "push_notification_config": {
      "$ref": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/core/push-notification-config.json",
      "description": "Optional webhook configuration for async update notifications. Publisher will send webhook when update completes if operation takes longer than immediate response time. This is separate from reporting_webhook which configures ongoing campaign reporting."
    },
    "idempotency_key": {
      "type": "string",
      "description": "Client-generated idempotency key for safe retries. If an update fails without a response, resending with the same idempotency_key guarantees the update is applied at most once. MUST be unique per (seller, request) pair to prevent cross-seller correlation. Use a fresh UUID v4 for each request.",
      "minLength": 16,
      "maxLength": 255,
      "pattern": "^[A-Za-z0-9_.:-]{16,255}$"
    },
    "context": {
      "$ref": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/core/context.json"
    },
    "ext": {
      "$ref": "https://adcontextprotocol.org/schemas/3.2.0-beta.0/core/ext.json"
    }
  },
  "required": [
    "idempotency_key",
    "account",
    "media_buy_id"
  ],
  "additionalProperties": true
}
