> ## Documentation Index
> Fetch the complete documentation index at: https://adcp-docs-ja.pier1.co.jp/llms.txt
> Use this file to discover all available pages before exploring further.

# update_media_buy

既存のメディアバイを PATCH セマンティクスで更新します。キャンペーン全体およびパッケージ単位の更新をサポートします。

**Response Time**: 即時〜日単位（`completed`、120 秒未満の `working`、または手動審査用の `submitted`）

## スコープ

`update_media_buy` は、`create_media_buy` で作成された購入だけでなく、[`get_media_buys`](/docs/media-buy/task-reference/get_media_buys) が返す任意の `media_buy_id` に対して動作します。セラーエージェントは、購入が元々 AdCP の外（アドサーバーへの直接入力、レガシー API、手動トラフィッキング）で作成されたことを理由に更新を拒否してはなりません（MUST NOT）。作成サーフェスは認可の軸としてサポートされていません。アカウントの所有権がその軸です。

ビジネス上の理由（契約上の義務、プラットフォームの制約、ポリシー）により特定のアクションが特定の購入でサポートされない場合、セラーは対応する更新を暗黙に拒否するのではなく、その購入の `valid_actions`（および `available_actions[]` の対応エントリ）からそのアクションのみを省略しなければなりません（MUST）。**作成サーフェスはビジネス上の理由ではありません。** セラーは、AdCP 外で作成された購入に対するその他の点で有効な更新に `INVALID_STATE` を返してはならず（MUST NOT）、AdCP 外で予約されたという理由だけで `valid_actions` が体系的に空の購入を返してはなりません（MUST NOT）——そのパターンは購入を隠すことと区別できず、[アカウント所有権 vs 作成サーフェス](/docs/media-buy/specification#account-ownership-vs-creation-surface)のルールに違反します。

## アクション語彙とフィールドマッピング

バイヤーはアクションを通じて意図を表現します。セラーは、構造化された `available_actions[]` フィールド（権威的）と、フラットな `valid_actions[]` フィールド（レガシー、4.0 で非推奨）を通じて、各購入で利用可能なアクションを宣言します。両フィールドが存在する場合、コンシューマーは `available_actions[]` を優先しなければなりません（MUST）——それは、フラットな文字列配列が表現できない解決済みの `mode`、任意の `sla`、任意の `terms_ref` を運びます。バイヤーが `update_media_buy` リクエストを発行すると、セラーはリクエストのフィールドを一つ以上のアクションにマップし、マップされたアクションが購入の解決済み `available_actions[]` にない場合は `ACTION_NOT_ALLOWED`（`error.details` に `attempted_action`、`reason`、`currently_available_actions` を伴う）で拒否します。

このマッピングは規範的です——セラーと SDK は、実装をまたいでサーフェスが一貫するよう、リクエストフィールドとアクション識別子の変換にこの表を使わなければなりません（MUST）。

| Action                | update\_media\_buy fields                                                     | Notes                                              |
| --------------------- | ----------------------------------------------------------------------------- | -------------------------------------------------- |
| `pause`               | `paused: true`                                                                |                                                    |
| `resume`              | `paused: false`                                                               |                                                    |
| `cancel`              | `canceled: true`, `cancellation_reason`                                       | 不可逆                                                |
| `extend_flight`       | `end_time`, `packages[].end_time`（現在より後）                                      | 終了日時の後ろ倒しのみ                                        |
| `shorten_flight`      | `end_time`, `packages[].end_time`（現在より前）                                      | 終了日時の前倒しのみ                                         |
| `update_flight_dates` | `start_time`, `end_time`, `packages[].start_time`, `packages[].end_time`（シフト） | 開始シフトは extend/shorten とは別。購入レベルとパッケージレベルの両方の日付をカバー |
| `increase_budget`     | `packages[].budget`（引き上げ）                                                     |                                                    |
| `decrease_budget`     | `packages[].budget`（引き下げ）                                                     | セラーは通常、消化済み額に制約される                                 |
| `reallocate_budget`   | `packages[].budget`（再配分、合計は不変）                                                |                                                    |

変化の方向を表すアクション（`extend_flight` / `shorten_flight`、`increase_budget` / `decrease_budget` / `reallocate_budget`）は `update_fields` のパスを共有します。アクションは、どのフィールドが設定されたかではなく、要求値を購入の現在状態と比較して決まります。サーバー側のディスパッチ強制は、正しいアクションを選ぶためにリクエストと現在状態を差分しなければならず（MUST）、解決されたアクションが購入の `available_actions[]` にない場合は `ACTION_NOT_ALLOWED` で拒否しなければなりません。

\| `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` | 他のターゲティングよりフライト中に再交渉されることが多い。フィールドは複数形ではなく単数の `frequency_cap`（単一ルール）。 |
\| `replace_creative` | `packages[].creatives[]` の入れ替え（割り当ては不変） | 割り当てセットの変更とは別の AM ワークフロー |
\| `update_creative_assignments` | `packages[].creative_assignments` | どのクリエイティブをどこに |
\| `remove_creative` | 置換ペイロードの `packages[].creatives[]` および/または `packages[].creative_assignments` からクリエイティブを省略 | 両配列は置換セマンティクスを使うため、削除は目的の事後状態をクリエイティブ不在で送ることで表現します（3.x に明示的な削除プリミティブはありません）。時間に敏感であり、追加/入れ替えに承認が必要な場合でも、セラーは self\_serve の削除をサポートすべきです（SHOULD） |
\| `add_packages` | `new_packages[]` |  |
\| `remove_packages` | `packages[].canceled: true` |  |

粗いレガシーアクション（`update_budget`、`update_dates`、`update_packages`、`sync_creatives`）は、3.0 の列挙サーフェスをまだ出しているセラー向けに、より細かい語彙を単一の値でカバーします。セラーはより細かいセットへ移行すべきです（SHOULD）。レガシー値は 4.0 で削除されます。

### アクションモード

`available_actions[]` の各エントリは、単数の `mode`（購入の現在状態に対して解決済み）を運びます。プロダクトレベルの `allowed_actions[]` テンプレートでは、プロダクトが複数の条件付きモードを提供しうる（例: 許容範囲内は `self_serve`、範囲外は `requires_approval` へエスカレーション）ため、フィールドは複数形の `modes[]` です。

| Mode                     | Meaning                                                                |
| ------------------------ | ---------------------------------------------------------------------- |
| `self_serve`             | セラーはリクエストを同期的に処理する                                                     |
| `conditional_self_serve` | 許容範囲内は自動承認し、範囲外はエスカレーションする（プログラマティック保証のパターン）                           |
| `requires_approval`      | Human-in-the-loop、非同期、プロポーザルのアーティファクトなし。バイヤー SDK はポーリングするか Webhook を待つ |

バイヤー SDK は、同期レスポンス・条件付き処理・非同期の承認コールバックのどれを期待するかを決めるため、`mode` で分岐しなければなりません（MUST）。リクオートは 3.1 ではアクションモードとしてモデル化されていません。要求された更新が現在の見積もりの範囲を超える場合、セラーは `REQUOTE_REQUIRED` を返します。

**PATCH セマンティクス**: 指定したフィールドのみ更新し、未指定フィールドは変更しません。

**Request Schema**: [`/schemas/v3/media-buy/update-media-buy-request.json`](https://adcontextprotocol.org/schemas/v3/media-buy/update-media-buy-request.json)
**Response Schema**: [`/schemas/v3/media-buy/update-media-buy-response.json`](https://adcontextprotocol.org/schemas/v3/media-buy/update-media-buy-response.json)

## クイックスタート

メディアバイを作成し、一時停止します。

<CodeGroup>
  ```javascript JavaScript theme={null}
  import { testAgent } from '@adcp/sdk/testing';
  import { CreateMediaBuyResponseSchema, UpdateMediaBuyResponseSchema } from '@adcp/sdk';

  // まず更新対象のメディアバイを作成
  const uniqueRef = `test_campaign_${Date.now()}`;

  // 開始/終了日は未来の日付を使用
  const startDate = new Date();
  startDate.setDate(startDate.getDate() + 7); // Start 1 week from now
  const endDate = new Date();
  endDate.setDate(endDate.getDate() + 37); // End 5 weeks from now

  const createResult = await testAgent.createMediaBuy({
    brand: { domain: 'acmecorp.com' },
    packages: [{
      product_id: 'prod_d979b543',
      pricing_option_id: 'cpm_usd_fixed',
      format_ids: [{
        agent_url: 'https://creative.adcontextprotocol.org',
        id: 'display_300x250_image'
      }],
      budget: 800,
      bid_price: 5.00
    }],
    start_time: startDate.toISOString(),
    end_time: endDate.toISOString()
  });

  if (!createResult.success) {
    throw new Error(`Create failed: ${createResult.error}`);
  }

  const created = CreateMediaBuyResponseSchema.parse(createResult.data);
  if ('errors' in created && created.errors) {
    throw new Error(`Create failed: ${JSON.stringify(created.errors)}`);
  }

  console.log(`Created media buy ${created.media_buy_id}`);

  // 続いてキャンペーンを一時停止
  const updateResult = await testAgent.updateMediaBuy({
    account: { brand: { domain: 'acmecorp.com' }, operator: 'acmecorp.com' },
    media_buy_id: created.media_buy_id,
    revision: created.revision,
    paused: true
  });

  if (!updateResult.success) {
    throw new Error(`Update failed: ${updateResult.error}`);
  }

  const updated = UpdateMediaBuyResponseSchema.parse(updateResult.data);
  if ('errors' in updated && updated.errors) {
    throw new Error(`Update failed: ${JSON.stringify(updated.errors)}`);
  }

  console.log(`Campaign ${updated.media_buy_id} paused`);
  ```

  ```python Python theme={null}
  import asyncio
  import time
  from datetime import datetime, timedelta
  from adcp.testing import test_agent

  async def create_and_pause_campaign():
      # まず更新対象のメディアバイを作成
      unique_ref = f"test_campaign_{int(time.time() * 1000)}"

      # 開始/終了日は未来の日付を使用
      start_date = datetime.utcnow() + timedelta(days=7)
      end_date = datetime.utcnow() + timedelta(days=37)

      create_result = await test_agent.simple.create_media_buy(
          brand={'domain': 'acmecorp.com'},
          packages=[{
              'product_id': 'prod_d979b543',
              'pricing_option_id': 'cpm_usd_fixed',
              'format_ids': [{
                  'agent_url': 'https://creative.adcontextprotocol.org',
                  'id': 'display_300x250_image'
              }],
              'budget': 800,
              'bid_price': 5.00
          }],
          start_time=start_date.strftime('%Y-%m-%dT%H:%M:%SZ'),
          end_time=end_date.strftime('%Y-%m-%dT%H:%M:%SZ')
      )

      if hasattr(create_result, 'errors') and create_result.errors:
          raise Exception(f"Create failed: {create_result.errors}")

      print(f"Created media buy {create_result.media_buy_id}")

      # 続いてキャンペーンを一時停止
      update_result = await test_agent.simple.update_media_buy(
          account={'brand': {'domain': 'acmecorp.com'}, 'operator': 'acmecorp.com'},
          media_buy_id=create_result.media_buy_id,
          revision=create_result.revision,
          paused=True
      )

      if hasattr(update_result, 'errors') and update_result.errors:
          raise Exception(f"Update failed: {update_result.errors}")

      print(f"Campaign {update_result.media_buy_id} paused")

  asyncio.run(create_and_pause_campaign())
  ```
</CodeGroup>

## リクエストパラメーター

| Parameter                  | Type                                                                                                  | Required | Description                                                                                                          |
| -------------------------- | ----------------------------------------------------------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------- |
| `account`                  | [account-ref](/docs/building/by-layer/L2/accounts-and-agents#account-references)                      | Yes      | このメディアバイを所有するアカウント。`{ "account_id": "..." }` または `{ "brand": {...}, "operator": "..." }` を渡します。ガバナンスチェックとアカウント解決に必要。 |
| `media_buy_id`             | string                                                                                                | Yes      | 更新対象のセラー側メディアバイ ID                                                                                                   |
| `revision`                 | integer                                                                                               | No       | 楽観的並行制御のための想定現在リビジョン。不一致の場合、セラーは `CONFLICT` で拒否します。`get_media_buys` または直近のレスポンスから取得します。                              |
| `start_time`               | string                                                                                                | No       | 更新後の開始日時                                                                                                             |
| `end_time`                 | string                                                                                                | No       | 更新後の終了日時                                                                                                             |
| `paused`                   | boolean                                                                                               | No       | メディアバイ全体を一時停止/再開（`true`=停止、`false`=稼働）                                                                               |
| `canceled`                 | boolean                                                                                               | No       | メディアバイ全体をキャンセル（不可逆）。存在する場合は `true` でなければなりません。セラーは `NOT_CANCELLABLE` で拒否しうる。                                         |
| `cancellation_reason`      | string                                                                                                | No       | キャンセルの理由                                                                                                             |
| `packages`                 | PackageUpdate\[]                                                                                      | No       | パッケージ単位の更新（下記参照）                                                                                                     |
| `reporting_webhook`        | object                                                                                                | No       | レポート用 Webhook 設定の更新（下記参照）                                                                                            |
| `idempotency_key`          | string                                                                                                | No       | 安全なリトライのための一意キー。同じキーの更新がすでに処理済みの場合、セラーは元のレスポンスを返します。（セラー、リクエスト）ペアごとに一意でなければなりません。最低 16 文字。                           |
| `invoice_recipient`        | [BusinessEntity](/docs/building/by-layer/L2/accounts-and-agents#billing-entity-and-invoice-recipient) | No       | この購入の請求書受取人を上書きします。セラーは認可を検証しなければならず（MUST）、ガバナンスエージェントが設定されている場合は `check_governance` に含めなければなりません。                   |
| `new_packages`             | PackageRequest\[]                                                                                     | No       | このメディアバイに追加する新規パッケージ。`create_media_buy` のパッケージと同じ形状。`valid_actions` に `add_packages` を宣言するセラーのみサポート。                 |
| `push_notification_config` | object                                                                                                | No       | 非同期処理通知用 Webhook                                                                                                     |

`account` と `media_buy_id` は常に必須です。

### 楽観的並行制御

`revision` は想定される現在のメディアバイのリビジョンです。一部の実装は内部的にこの値を `expected_revision` と呼びますが、AdCP のワイヤー上のフィールドは `revision` です。後方互換のためこのフィールドは任意です。存在する場合、セラーは変更を伴う更新を適用する書き込みとアトミックにこれをチェックしなければなりません（MUST）。アプリケーションコードで現在値を読み、比較し、後で書き込むと、別のライターと競合して更新を失う可能性があります。保存されたリビジョンがリクエストの `revision` と異なる場合、セラーは `CONFLICT` で拒否し、変更を一切適用しません。

変更を伴うすべての更新は `revision` をインクリメントし、成功レスポンスで新しい値を返します。検証のみのリクエスト、読み取り、厳密な冪等リプレイはインクリメントしません。厳密なリプレイは以前のリビジョンを返します。クライアントは、状態変更を意図するすべての更新で最後に観測したリビジョンを渡し、`CONFLICT` を受け取ったら `get_media_buys` で再読み込みして新しい `idempotency_key` でリトライすべきです（SHOULD）。

### Reporting Webhook オブジェクト

このメディアバイの自動レポート配信を設定します。

| Parameter             | Type      | Required | Description                       |
| --------------------- | --------- | -------- | --------------------------------- |
| `url`                 | string    | Yes      | Webhook エンドポイント URL               |
| `authentication`      | object    | Yes      | `schemes` と `credentials` を持つ認証設定 |
| `reporting_frequency` | string    | Yes      | `hourly` / `daily` / `monthly`    |
| `requested_metrics`   | string\[] | No       | 取得したい指標（未指定ならすべて）                 |
| `token`               | string    | No       | 検証用のクライアントトークン（16 文字以上）           |

**Note**: `reporting_webhook` はキャンペーンの継続レポート設定、`push_notification_config` は「この更新が完了したら知らせて」といった非同期通知用です。

### Package Update オブジェクト

| Parameter                  | Type                  | Description                                                                                                                                                                                                                                                       |
| -------------------------- | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `package_id`               | string                | 更新対象のセラー側パッケージ ID                                                                                                                                                                                                                                                 |
| `paused`                   | boolean               | パッケージ単位で一時停止/再開（`true`=停止、`false`=稼働）                                                                                                                                                                                                                             |
| `canceled`                 | boolean               | このパッケージをキャンセル（不可逆）。存在する場合は `true` でなければなりません。セラーは `NOT_CANCELLABLE` で拒否しうる。                                                                                                                                                                                       |
| `cancellation_reason`      | string                | このパッケージをキャンセルする理由                                                                                                                                                                                                                                                 |
| `budget`                   | number                | 予算の更新値                                                                                                                                                                                                                                                            |
| `impressions`              | number                | このパッケージのインプレッション目標の更新値                                                                                                                                                                                                                                            |
| `start_time`               | string                | 更新後のフライト開始日時（ISO 8601）。メディアバイの日付範囲内である必要があります。                                                                                                                                                                                                                    |
| `end_time`                 | string                | 更新後のフライト終了日時（ISO 8601）。メディアバイの日付範囲内である必要があります。                                                                                                                                                                                                                    |
| `pacing`                   | string                | ペーシング戦略の更新                                                                                                                                                                                                                                                        |
| `bid_price`                | number                | 入札額の更新（オークション商品のみ）。選択した価格オプションに `max_bid: true` がない限り、これは尊重すべき正確な入札/価格です。`max_bid: true` の場合はバイヤーの最大支払い意思額（上限）として扱われます。                                                                                                                                           |
| `optimization_goals`       | OptimizationGoal\[]   | このパッケージの最適化目標をすべて置き換えます。置換セマンティクスを使用——省略すると目標は変更されません。                                                                                                                                                                                                            |
| `targeting_overlay`        | TargetingOverlay      | ターゲティング制約の更新。置換セマンティクスを使用。`signal_targeting_groups` の変更は価格付きシグナル選択を変えうるため、選択されたシグナル・グループ式・シグナルの `pricing_option_id` が元の見積もりの範囲外になる場合、セラーは `REQUOTE_REQUIRED` で拒否してよい（MAY）。セラーは固定シグナル選択の変更を拒否すべきであり（SHOULD）、適用された固定/デフォルトのシグナルグループを結果のパッケージ状態でエコーしなければなりません（MUST）。 |
| `catalogs`                 | Catalog\[]            | このパッケージが宣伝するカタログを置き換えます。置換セマンティクスを使用——省略すると変更されません。                                                                                                                                                                                                               |
| `keyword_targets_add`      | KeywordTarget\[]      | (keyword, match\_type) の同一性で追加またはアップサートするキーワードターゲット。作成時、これらは `targeting_overlay` 内の `keyword_targets` として設定されます。                                                                                                                                                  |
| `keyword_targets_remove`   | KeywordTarget\[]      | (keyword, match\_type) の同一性で削除するキーワードターゲット。                                                                                                                                                                                                                       |
| `negative_keywords_add`    | NegativeKeyword\[]    | このパッケージに追加する除外キーワード。作成時、これらは `targeting_overlay` 内の `negative_keywords` として設定されます。                                                                                                                                                                                |
| `negative_keywords_remove` | NegativeKeyword\[]    | このパッケージから削除する除外キーワード。                                                                                                                                                                                                                                             |
| `creative_assignments`     | CreativeAssignment\[] | 割り当て済みライブラリクリエイティブを置き換え（重み/プレースメント指定可）                                                                                                                                                                                                                            |
| `creatives`                | CreativeAsset\[]      | このパッケージの割り当て済みインラインクリエイティブ本体を置き換えます。`media_buy.features.inline_creative_management: true` が必要。セラーが `creative.has_creative_library: true` も宣言する場合、新しい `creative_id` 値はライブラリに既存であってはなりません。                                                                          |

`package_id` は更新対象のパッケージを識別するために必須です。

## レスポンス

### 成功レスポンス

| Field                 | Description                                                                                                                                                                               |
| --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `media_buy_id`        | メディアバイ ID                                                                                                                                                                                 |
| `media_buy_status`    | 更新後のメディアバイのライフサイクルステータス（ステータスが変わる場合に存在。例: キャンセル）。3.1 の正準フィールド。[移行 › `media_buy_status`](/docs/reference/migration/media-buy-status) 参照。                                                   |
| `status`              | **3.1 で非推奨、3.2 で削除**（[#4906](https://github.com/adcontextprotocol/adcp/issues/4906)）。代わりに `media_buy_status` を使用してください。トップレベルの `status` は、フラットにシリアライズされた MCP ワイヤー上でエンベロープのタスクステータスと衝突します。 |
| `revision`            | この更新後のリビジョン番号。楽観的並行制御のため、状態変更を意図する後続リクエストで使用します。厳密な冪等リプレイは以前のリビジョンを返します。                                                                                                                  |
| `implementation_date` | 変更が反映される日時 (ISO 8601)。承認待ちの場合は null                                                                                                                                                       |
| `invoice_recipient`   | 更新された請求書受取人。指定された場合にリクエストからエコーされます。セラーが請求の上書きを受諾したことを確認します。銀行詳細は省略されます（書き込み専用）。                                                                                                           |
| `valid_actions`       | この更新後にバイヤーが実行できるフラット語彙のアクション。`get_media_buys` への往復を節約します。`available_actions[]` の登場により非推奨、4.0 で削除。                                                                                         |
| `available_actions`   | この更新後に利用可能なアクションの、購入ごとの構造化された解決。各エントリはアクション、解決済み `mode`、任意の `sla`、任意の `terms_ref` を持ちます。権威的——両方が存在する場合、バイヤー SDK はこれを `valid_actions` より優先すべきです（SHOULD）。                                   |
| `affected_packages`   | パッケージレベルの更新について、直接変更された各パッケージの更新後の完全な状態を示す Package オブジェクト配列。これは疎な差分ではなく状態のスナップショットです: セラーは `{ package_id }` のみのスタブを返してはなりません（MUST NOT）。パッケージを変更しないキャンペーンレベルの更新は空配列を返しうる。                  |

### エラーレスポンス

| Field    | Description                               |
| -------- | ----------------------------------------- |
| `errors` | Array of error objects explaining failure |

**Note**: レスポンスは判別可能なユニオン。成功フィールドか errors のどちらかのみ返されるため、成功フィールドにアクセスする前に `errors` を確認してください。

## 主なシナリオ

### パッケージ予算の更新

特定パッケージの予算を増額:

<CodeGroup>
  ```javascript test=false JavaScript theme={null}
  import { testAgent } from '@adcp/sdk/testing';
  import { UpdateMediaBuyResponseSchema } from '@adcp/sdk';

  const result = await testAgent.updateMediaBuy({
    media_buy_id: 'mb_12345',
    packages: [{
      package_id: 'pkg_001',
      budget: 50000  // Increased from 30000
    }]
  });

  if (!result.success) {
    throw new Error(`Request failed: ${result.error}`);
  }

  const validated = UpdateMediaBuyResponseSchema.parse(result.data);

  if ('errors' in validated && validated.errors) {
    throw new Error(`Update failed: ${JSON.stringify(validated.errors)}`);
  }

  const pkg = validated.affected_packages?.find(p => p.package_id === 'pkg_001');
  if (pkg) {
    console.log(`Package budget updated to ${pkg.budget}`);
  }
  ```

  ```python test=false Python theme={null}
  import asyncio
  from adcp.testing import test_agent
  from adcp.types import UpdateMediaBuyRequest

  async def increase_budget():
      result = await test_agent.update_media_buy(
          UpdateMediaBuyRequest(
              media_buy_id='mb_12345',
              packages=[
                  {'package_id': 'pkg_001', 'budget': 50000}
              ]
          )
      )

      if hasattr(result, 'errors') and result.errors:
          raise Exception(f"Update failed: {result.errors}")

      pkg = next((p for p in result.affected_packages if p.package_id == 'pkg_001'), None)
      if pkg:
          print(f"Package budget updated to {pkg.budget}")

  asyncio.run(increase_budget())
  ```
</CodeGroup>

### キャンペーン日程の変更

キャンペーン終了日を延長:

<CodeGroup>
  ```javascript test=false JavaScript theme={null}
  import { testAgent } from '@adcp/sdk/testing';
  import { UpdateMediaBuyResponseSchema } from '@adcp/sdk';

  const result = await testAgent.updateMediaBuy({
    account: { account_id: 'acc_acme_001' },
    media_buy_id: 'mb_12345',
    end_time: '2025-09-30T23:59:59Z'
  });

  if (!result.success) {
    throw new Error(`Request failed: ${result.error}`);
  }

  const validated = UpdateMediaBuyResponseSchema.parse(result.data);

  if ('errors' in validated && validated.errors) {
    throw new Error(`Update failed: ${JSON.stringify(validated.errors)}`);
  }

  console.log('Campaign end date extended');
  console.log(`Effective: ${validated.implementation_date}`);
  ```

  ```python test=false Python theme={null}
  import asyncio
  from adcp.testing import test_agent
  from adcp.types import UpdateMediaBuyRequest

  async def extend_campaign():
      result = await test_agent.update_media_buy(
          UpdateMediaBuyRequest(
              account={'account_id': 'acc_acme_001'},
              media_buy_id='mb_12345',
              end_time='2025-09-30T23:59:59Z'
          )
      )

      if hasattr(result, 'errors') and result.errors:
          raise Exception(f"Update failed: {result.errors}")

      print('Campaign end date extended')
      print(f"Effective: {result.implementation_date}")

  asyncio.run(extend_campaign())
  ```
</CodeGroup>

### ターゲティングの更新

地理制限を追加・変更:

<CodeGroup>
  ```javascript test=false JavaScript theme={null}
  import { testAgent } from '@adcp/sdk/testing';
  import { UpdateMediaBuyResponseSchema } from '@adcp/sdk';

  const result = await testAgent.updateMediaBuy({
    media_buy_id: 'mb_12345',
    packages: [{
      package_id: 'pkg_001',
      targeting_overlay: {
        geo_country_any_of: ['US', 'CA'],
        geo_region_any_of: ['CA', 'NY', 'TX', 'ON', 'QC']
      }
    }]
  });

  if (!result.success) {
    throw new Error(`Request failed: ${result.error}`);
  }

  const validated = UpdateMediaBuyResponseSchema.parse(result.data);

  if ('errors' in validated && validated.errors) {
    throw new Error(`Update failed: ${JSON.stringify(validated.errors)}`);
  }

  console.log('Targeting updated successfully');
  ```

  ```python test=false Python theme={null}
  import asyncio
  from adcp.testing import test_agent
  from adcp.types import UpdateMediaBuyRequest

  async def update_targeting():
      result = await test_agent.update_media_buy(
          UpdateMediaBuyRequest(
              media_buy_id='mb_12345',
              packages=[
                  {
                      'package_id': 'pkg_001',
                      'targeting_overlay': {
                          'geo_country_any_of': ['US', 'CA'],
                          'geo_region_any_of': ['CA', 'NY', 'TX', 'ON', 'QC']
                      }
                  }
              ]
          )
      )

      if hasattr(result, 'errors') and result.errors:
          raise Exception(f"Update failed: {result.errors}")

      print('Targeting updated successfully')

  asyncio.run(update_targeting())
  ```
</CodeGroup>

### Replace Creatives

Swap out creative assignments for a package:

<CodeGroup>
  ```javascript test=false JavaScript theme={null}
  import { testAgent } from '@adcp/sdk/testing';
  import { UpdateMediaBuyResponseSchema } from '@adcp/sdk';

  const result = await testAgent.updateMediaBuy({
    media_buy_id: 'mb_12345',
    packages: [{
      package_id: 'pkg_001',
      creative_assignments: [
        { creative_id: 'creative_video_v2' },
        { creative_id: 'creative_display_v2', weight: 60 }
      ]
    }]
  });

  if (!result.success) {
    throw new Error(`Request failed: ${result.error}`);
  }

  const validated = UpdateMediaBuyResponseSchema.parse(result.data);

  if ('errors' in validated && validated.errors) {
    throw new Error(`Update failed: ${JSON.stringify(validated.errors)}`);
  }

  const pkg = validated.affected_packages?.find(p => p.package_id === 'pkg_001');
  const assignmentCount = pkg?.creative_assignments?.length || 0;
  console.log(`Assigned ${assignmentCount} creatives`);
  ```

  ```python test=false Python theme={null}
  import asyncio
  from adcp.testing import test_agent
  from adcp.types import UpdateMediaBuyRequest

  async def replace_creatives():
      result = await test_agent.update_media_buy(
          UpdateMediaBuyRequest(
              media_buy_id='mb_12345',
              packages=[
                  {
                      'package_id': 'pkg_001',
                      'creative_assignments': [
                          {'creative_id': 'creative_video_v2'},
                          {'creative_id': 'creative_display_v2', 'weight': 60}
                      ]
                  }
              ]
          )
      )

      if hasattr(result, 'errors') and result.errors:
          raise Exception(f"Update failed: {result.errors}")

      pkg = next((p for p in result.affected_packages if p.package_id == 'pkg_001'), None)
      assignment_count = len(pkg.creative_assignments) if pkg and pkg.creative_assignments else 0
      print(f"Assigned {assignment_count} creatives")

  asyncio.run(replace_creatives())
  ```
</CodeGroup>

### Multiple Package Updates

Update multiple packages in one call:

<CodeGroup>
  ```javascript test=false JavaScript theme={null}
  import { testAgent } from '@adcp/sdk/testing';
  import { UpdateMediaBuyResponseSchema } from '@adcp/sdk';

  const result = await testAgent.updateMediaBuy({
    media_buy_id: 'mb_12345',
    packages: [
      {
        package_id: 'pkg_001',
        budget: 50000,
        pacing: 'front_loaded'
      },
      {
        package_id: 'pkg_002',
        budget: 30000,
        paused: true
      }
    ]
  });

  if (!result.success) {
    throw new Error(`Request failed: ${result.error}`);
  }

  const validated = UpdateMediaBuyResponseSchema.parse(result.data);

  if ('errors' in validated && validated.errors) {
    throw new Error(`Update failed: ${JSON.stringify(validated.errors)}`);
  }

  console.log(`Updated ${validated.affected_packages?.length || 0} packages`);
  ```

  ```python test=false Python theme={null}
  import asyncio
  from adcp.testing import test_agent
  from adcp.types import UpdateMediaBuyRequest

  async def update_multiple_packages():
      result = await test_agent.update_media_buy(
          UpdateMediaBuyRequest(
              media_buy_id='mb_12345',
              packages=[
                  {
                      'package_id': 'pkg_001',
                      'budget': 50000,
                      'pacing': 'front_loaded'
                  },
                  {
                      'package_id': 'pkg_002',
                      'budget': 30000,
                      'paused': True
                  }
              ]
          )
      )

      if hasattr(result, 'errors') and result.errors:
          raise Exception(f"Update failed: {result.errors}")

      print(f"Updated {len(result.affected_packages)} packages")

  asyncio.run(update_multiple_packages())
  ```
</CodeGroup>

### メディアバイのキャンセル

メディアバイ全体をキャンセルします:

```json theme={null}
{
  "account": { "account_id": "acc_acme_001" },
  "media_buy_id": "mb_12345",
  "canceled": true,
  "cancellation_reason": "Campaign strategy changed"
}
```

**成功レスポンス:**

```json theme={null}
{
  "media_buy_id": "mb_12345",
  "media_buy_status": "canceled",
  "revision": 4,
  "implementation_date": "2025-06-15T10:00:00Z",
  "affected_packages": []
}
```

ボディレベルの `media_buy_status` が、購入のライフサイクル状態に関する 3.1 の正準フィールドです。レガシーのトップレベル `status: MediaBuyStatus` 形式（例: `"status": "canceled"`）は非推奨で、3.2 で削除されます（[#4906](https://github.com/adcontextprotocol/adcp/issues/4906)）——それは同じルートキーでエンベロープのタスクステータスと衝突していました。移行については[移行 › `media_buy_status`](/docs/reference/migration/media-buy-status)を参照してください。

**`NOT_CANCELLABLE` エラーレスポンス:**

```json theme={null}
{
  "errors": [{
    "code": "NOT_CANCELLABLE",
    "message": "Media buy mb_12345 has contractual obligations preventing cancellation",
    "suggestion": "Contact seller to discuss cancellation options"
  }]
}
```

**`INVALID_STATE` エラーレスポンス**（例: 完了したメディアバイを更新しようとした場合）:

```json theme={null}
{
  "errors": [{
    "code": "INVALID_STATE",
    "message": "Media buy mb_12345 is in terminal state 'completed' and cannot be modified",
    "suggestion": "Check current status via get_media_buys and adjust request"
  }]
}
```

**`REQUOTE_REQUIRED` エラーレスポンス**（更新が、見積もりの価格算定基準となったパラメータの範囲を変える場合）:

```json theme={null}
{
  "errors": [{
    "code": "REQUOTE_REQUIRED",
    "message": "Doubling budget and extending end_time into Q4 changes the pricing basis of the current buy",
    "details": {
      "envelope_field": ["packages[0].budget", "end_time"]
    },
    "suggestion": "Adjust the update to stay within the current quote envelope, rediscover products/terms, add packages when available, or create a separate media buy"
  }]
}
```

### パッケージのキャンセル

メディアバイをアクティブなまま、単一のパッケージをキャンセルします:

```json theme={null}
{
  "account": { "account_id": "acc_acme_001" },
  "media_buy_id": "mb_12345",
  "packages": [
    {
      "package_id": "pkg_67890",
      "canceled": true,
      "cancellation_reason": "Underperforming — reallocating budget"
    }
  ]
}
```

## 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)

❌ **Cannot update:**

* 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`)

❌ **Cannot update (schema-enforced via `not` constraint on `package-update.json`):**

* Package ID
* Product ID
* Pricing option ID
* Format selectors: `format_ids`, `format_option_refs`, `format_kind`, and `params` (creatives must match existing formats)

⚠️ **Append-only on update:**

* `committed_metrics` — セラーは新しいエントリ（フライト中のメトリクス追加。それぞれ独自の `committed_at` タイムスタンプを持つ）を受け入れますが、既存エントリを変更または削除しようとする試みを `validation_error`（コード `IMMUTABLE_FIELD`）で拒否しなければなりません（MUST）。ランタイムでの強制です。追記専用のセマンティクスはスキーマの `not` 節では表現できません。

## 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 the seller's creative namespace                                                                                   | For library-backed sellers, assign existing creatives via `creative_assignments` or update via `sync_creatives`; for inline-only sellers, use a different package-scoped `creative_id`                                                                                                             |
| `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                                                                                                                                                                                                                                                    |

Example error response:

```json theme={null}
{
  "errors": [{
    "code": "UNSUPPORTED_FEATURE",
    "message": "Cannot change product_id for existing package",
    "field": "packages[0].product_id",
    "suggestion": "Create a new package with the desired product instead"
  }]
}
```

## 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

When approval is needed, `implementation_date` will be `null`:

```json theme={null}
{
  "media_buy_id": "mb_12345",
  "implementation_date": null,
  "affected_packages": []
}
```

## PATCH Semantics

Only specified fields are updated - omitted fields remain unchanged:

```json theme={null}
{
  "account": { "account_id": "acc_acme_001" },
  "media_buy_id": "mb_12345",
  "packages": [{
    "package_id": "pkg_001",
    "budget": 50000
  }]
}
```

**Array replacement**: When updating arrays (like `creative_assignments`), provide the complete new array:

```json theme={null}
{
  "account": { "account_id": "acc_acme_001" },
  "media_buy_id": "mb_12345",
  "packages": [{
    "package_id": "pkg_001",
    "creative_assignments": [
      { "creative_id": "creative_video_v2" },
      { "creative_id": "creative_display_v2", "weight": 60 }
    ]
  }]
}
```

## Asynchronous Operations

Updates may be asynchronous, especially with seller approval.

### Response Patterns

**Synchronous (completed immediately)**:

```json theme={null}
{
  "media_buy_id": "mb_12345",
  "implementation_date": "2025-06-15T10:00:00Z",
  "affected_packages": []
}
```

**Asynchronous (processing)**:

```json theme={null}
{
  "status": "working",
  "message": "Processing update..."
}
```

Poll for completion or use webhooks/streaming.

**Manual Approval Required**:

```json theme={null}
{
  "status": "submitted",
  "message": "Update requires seller approval (2-4 hours)"
}
```

Will take hours to days.

### 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

See [Async Operations](/docs/building/by-layer/L3/async-operations) for protocol-specific async patterns and examples.

## 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 and `implementation_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_date` indicates when changes take effect (null if pending approval)
* **Inline creatives**: `creatives` 配列はパッケージのインラインクリエイティブ本体を置き換えます。セラーが `creative.has_creative_library: true` を宣言する場合、既存のライブラリクリエイティブを更新するには [`sync_creatives`](/docs/creative/task-reference/sync_creatives) を、既存のライブラリクリエイティブを割り当てるには `creative_assignments` を使用します。セラーがクリエイティブライブラリなしで `inline_creative_management: true` を宣言する場合、インラインクリエイティブの追加・置換・削除のワークフローにはここの `packages[].creatives` を使用します。

<Note>
  **キャンペーンガバナンス — 変更フェーズ**

  バイヤーのアカウントにガバナンスエージェントが設定されている場合、セラーは更新を確定する前に、`media_buy_id`、`planned_delivery`、`phase: "modification"` を伴って [`check_governance`](/docs/governance/campaign/tasks/check_governance) を呼び出さなければなりません（MUST）。ガバナンスエージェントは、変更の大きさ、予算の再配分、新しいパラメータをキャンペーンプランに対して検証します。

  完全な実行チェックのワークフローとコード例は[セラー統合ガイド](/docs/building/operating/seller-integration#execution-checks)を参照してください。
</Note>

## Next Steps

After updating a media buy:

1. **Verify Changes**: Use [`get_media_buy_delivery`](/docs/media-buy/task-reference/get_media_buy_delivery) to confirm updates
2. **Upload New Creatives**: Use [`sync_creatives`](/docs/creative/task-reference/sync_creatives) if creative assignments changed
3. **Monitor Performance**: Track impact of changes on campaign metrics
4. **Optimize Further**: Use [`provide_performance_feedback`](/docs/media-buy/task-reference/provide_performance_feedback) for ongoing optimization

## Learn More

* [Media Buy Lifecycle](/docs/media-buy/media-buys/) - Complete campaign workflow
* [Targeting](/docs/media-buy/advanced-topics/targeting) - Targeting overlays and restrictions
* [Async Operations](/docs/building/by-layer/L3/async-operations) - Async patterns and status checking
* [create\_media\_buy](/docs/media-buy/task-reference/create_media_buy) - Initial campaign creation
