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

# sync_accounts

> sync_accounts は、バイヤー宣言アカウントをプロビジョニングするか、AdCP セラーエージェントで既存アカウントの設定を更新します。

1つ以上のブランド/オペレーターのペアに対してセラーと広告主アカウントを同期するか、セラーがそのモードを公開する場合は既存アカウントの設定を更新します。ブランドは `domain` + オプションの `brand_id` を含む `brand` オブジェクトで識別され、`/.well-known/brand.json` 経由で解決されます。

`sync_accounts` はすべてのセラープロトコルで使用されます: メディアバイエージェント、シグナルエージェント、ガバナンスエージェント、クリエイティブエージェント。プロビジョニングモードでは、バイヤーの意図を宣言し、セラーが内部でアカウントをプロビジョニングまたはリンクします。バイヤー宣言アカウント（`require_operator_auth: false`）にはプロビジョニングモードを使い、後続のリクエストには自然キー（`brand` + `operator`）を使用します。セラーは内部ハンドルとして `account_id` をエコーしてもよい（MAY）が、この方法でプロビジョニングされたアカウントについて自然キーの `AccountRef` を受け入れ続けなければなりません（MUST）。アカウント ID 名前空間では、セラーが割り当てたアカウント ID を [`list_accounts`](/docs/accounts/tasks/list_accounts) またはアウトオブバンドのオンボーディングで探索します。アカウント ID 名前空間の `sync_accounts` プロビジョニングは、将来の明示的なケイパビリティがそのモードを宣言しない限りスコープ外です。そのようなセラーが今日 `sync_accounts` を公開する場合、`account_id` でキーされる設定更新モードにのみ使用します。

**応答時間**: 約1秒。アカウントプロビジョニングは同期的; 与信審査や法的レビューには人間の対応が必要な場合がある（`setup.url` 付きの `status: "pending_approval"` で示されます）。

**リクエストスキーマ**: [`/schemas/v3/account/sync-accounts-request.json`](https://adcontextprotocol.org/schemas/v3/account/sync-accounts-request.json)
**レスポンススキーマ**: [`/schemas/v3/account/sync-accounts-response.json`](https://adcontextprotocol.org/schemas/v3/account/sync-accounts-response.json)

## クイックスタート

単一の広告主アカウントを同期して結果のステータスを確認します。

<CodeGroup>
  ```javascript JavaScript theme={null}
  import { testAgent } from "@adcp/sdk/testing";
  import { SyncAccountsResponseSchema } from "@adcp/sdk";

  const result = await testAgent.syncAccounts({
    accounts: [
      {
        brand: { domain: "acme-corp.com" },
        operator: "acme-corp.com",
        billing: "operator",
      },
    ],
  });

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

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

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

  for (const account of validated.accounts) {
    console.log(`${account.brand.domain}: ${account.status}`);
    if (account.status === "pending_approval" && account.setup?.url) {
      console.log(`  Complete setup at: ${account.setup.url}`);
    }
  }
  ```

  ```python Python theme={null}
  import asyncio
  from adcp.testing import test_agent

  async def main():
      result = await test_agent.simple.sync_accounts(
          accounts=[
              {
                  "brand": {"domain": "acme-corp.com"},
                  "operator": "acme-corp.com",
                  "billing": "operator",
              },
          ],
      )

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

      for account in result.accounts:
          print(f"{account.brand['domain']}: {account.status}")
          if account.status == 'pending_approval' and hasattr(account, 'setup') and account.setup:
              print(f"  Complete setup at: {account.setup.url}")

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

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

| パラメーター                     | 型       | 必須  | 説明                                                                                          |
| -------------------------- | ------- | --- | ------------------------------------------------------------------------------------------- |
| `accounts`                 | array   | Yes | 同期するアカウントエントリの配列（下記参照）。                                                                     |
| `delete_missing`           | boolean | No  | true の場合、このエージェントが以前に同期したがこのリクエストに含まれないアカウントを非アクティブ化します。認証済みエージェントにスコープされます。デフォルト: `false`。 |
| `dry_run`                  | boolean | No  | true の場合、変更を適用せずにプレビューします。デフォルト: `false`。                                                   |
| `push_notification_config` | object  | No  | アカウントステータス変更時の非同期通知用 Webhook（例: `pending_approval` から `active` への遷移）。                       |

**アカウントエントリのフィールド:**

| フィールド                  | 型       | 必須  | 説明                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| ---------------------- | ------- | --- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `brand`                | object  | Yes | 広告主を識別するブランド参照。`domain`（brand.json がホストされているハウスドメイン）とオプションの `brand_id`（マルチブランドハウス用）を含みます。[brand-ref](/docs/brand-protocol/brand-json) を参照。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `operator`             | string  | Yes | ブランドの代理で活動するエンティティのドメイン（例: `pinnacle-media.com`）。ブランドが直接運営する場合はブランドのドメインに設定。brand.json の `authorized_operators` に対して検証されます。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `billing`              | string  | Yes | 請求先: `operator`、`agent`、`advertiser`。セラーがケイパビリティレベルで受け入れる内容を確認するには `get_adcp_capabilities` の `supported_billing` を確認します。セラーはこの請求モデルを受け入れるかリクエストを拒否しなければなりません。セラーは、セラー全体のケイパビリティが受け入れる値でも、呼び出しバイヤーエージェントの商業関係が許可しない場合は追加で拒否してもよい（MAY）— 例: パススルー専用としてオンボードされたバイヤーエージェント（支払い関係なし — オペレーターのみが請求され得る）。2 つのゲートは別個のエラーコードを使います — セラー全体のケイパビリティゲートには `BILLING_NOT_SUPPORTED`、バイヤーエージェントごとのゲートには `BILLING_NOT_PERMITTED_FOR_AGENT` — ためエージェントはプロースを解析せずに自律リトライ vs 人間オンボーディングにディスパッチできます。[バイヤーエージェントのアイデンティティ](/docs/building/by-layer/L2/accounts-and-agents#buyer-agent-identity)と [Billing and Account Setup](/docs/building/by-layer/L3/error-handling#billing-and-account-setup) を参照。 |
| `billing_entity`       | object  | No  | 支払責任を負う当事者の構造化されたビジネスエンティティ詳細。`legal_name`（必須）に加え、オプションで `vat_id`、`tax_id`、`registration_number`、`address`、`contacts`、`bank`。銀行詳細は書き込み専用 — リクエストに含めるがレスポンスでエコーされない。[請求エンティティとインボイス受取人](/docs/building/by-layer/L2/accounts-and-agents#billing-entity-and-invoice-recipient)を参照。                                                                                                                                                                                                                                                                                                                                                                                                  |
| `payment_terms`        | string  | No  | このアカウントの支払い条件: `net_15`、`net_30`、`net_45`、`net_60`、`net_90`、`prepay`。セラーはこれらの条件を受け入れるかアカウントを拒否しなければなりません — 条件は暗黙的に変更されない。省略時、セラーはデフォルト条件を適用します。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `sandbox`              | boolean | No  | true の場合、実際のプラットフォーム呼び出しや請求なしでサンドボックスアカウントを設定します。バイヤー宣言アカウント（`require_operator_auth: false`）にのみ適用。アカウント ID 名前空間の場合、サンドボックスアカウントは `list_accounts` で探索するかアウトオブバンドで供給される既存のテストアカウント。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `notification_configs` | array   | No  | 単一のメディアバイより長く続くイベント向けのアカウントレベル Webhook サブスクライバー: クリエイティブライフサイクル通知とホールセールフィード変更 Webhook。省略すると既存のサブスクライバーを変更しない。`[]` を送るとすべてのサブスクライバーを削除。完全な配列を送ると置き換え。エントリはアカウントスコープの `subscriber_id` でキーされる。既存の `subscriber_id` はアップサートされ、送信配列に不在の永続化 ID は削除される。                                                                                                                                                                                                                                                                                                                                                                                                                                 |

**自然キー**: タプル `(brand, operator, sandbox)` がアカウント関係を一意に識別します。`{brand: {domain: "acme-corp.com"}, operator: "acme-corp.com"}`（直接）は `{brand: {domain: "acme-corp.com"}, operator: "pinnacle-media.com"}`（代理店経由）とは異なるアカウント。`sandbox: true` を追加すると、同じブランド/オペレーターのペアに対してサンドボックスアカウントがプロビジョニングされる — 実際のプラットフォーム呼び出しや請求なし。

## レスポンス

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

アカウントごとの結果を含む `accounts` 配列を返します。操作が成功しても、個々のアカウントが保留中、拒否、または失敗することがあります。

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

* `errors` -- 操作レベルのエラーの配列（認証失敗、サービス利用不可）。`accounts` 配列は含まれない。

**注:** レスポンスは判別共用体を使用 -- `accounts` または `errors` のいずれか一方のみ、両方は含まれない。

**アカウントごとのフィールド:**

| フィールド                  | 説明                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `brand`                | リクエストからエコーされます。`domain` とオプションの `brand_id` を含むオブジェクト。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `operator`             | リクエストからエコーされます。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `name`                 | アカウントのセラー表示名。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `action`               | 実行された内容: `created`、`updated`、`unchanged`、`failed`。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `status`               | アカウントの現在の状態（[アカウントステータス](#account-status) を参照）。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `billing`              | 適用された請求モデル。リクエストの値と一致します。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `billing_entity`       | 請求される当事者のビジネスエンティティ詳細、リクエストからエコー。セラーはエージェントが省略したフィールド（例: 与信チェックからの `registration_number`）を追加してもよいが、異なるエンティティのデータを返してはならない。銀行詳細は省略（書き込み専用）。                                                                                                                                                                                                                                                                                                                                                                                                      |
| `account_scope`        | セラーがアカウントをスコープした方法: `operator`（このオペレーターのブランド間で共有）、`brand`（このブランドのオペレーター間で共有）、`operator_brand`（このオペレーター+ブランドのペア専用）、`agent`（宣言されたブランド/オペレーターのペア間で共有されるエージェントスコープのアカウント）。[アカウントスコープ](/docs/building/by-layer/L2/accounts-and-agents#account-scope) を参照。                                                                                                                                                                                                                                                                                            |
| `setup`                | `status: "pending_approval"` の場合に存在。与信または法的セットアップ完了の `url`、必要な内容を説明する `message`、オプションの `expires_at` を含みます。                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `rate_card`            | セラーが割り当てたレートカード識別子（該当する場合）。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `payment_terms`        | このアカウントで合意した支払い条件: `net_15`、`net_30`、`net_45`、`net_60`、`net_90`、`prepay`。アカウントがアクティブな場合、すべての請求書の拘束力を持つ条件。                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `credit_limit`         | 最大未払い残高（`{amount, currency}`）。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `errors`               | アカウントごとのエラー（`action: "failed"` の場合のみ存在）。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `warnings`             | 非致命的な通知。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `sandbox`              | これがサンドボックスアカウントかどうか、リクエストからエコーされます。バイヤー宣言アカウントにのみ存在。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `notification_configs` | オプション。リクエスト適用後の現在の永続化されたアカウントレベル Webhook サブスクライバー。リクエストが `notification_configs` を含んだか、アカウントがすでに永続化されたサブスクライバーを持つ場合、`created`、`updated`、`unchanged` の結果で存在。各エントリは `subscriber_id`、`url`、`event_types[]`、`active` を運ぶ。`authentication.credentials` は省略（書き込み専用）。                                                                                                                                                                                                                                                                                   |
| `authorization`        | オプション。このアカウントに対する呼び出しエージェントのスコープ付与 — `allowed_tasks`、`field_scopes`、`scope_name`、`read_only`。すべてのベンダーエージェントタイプ（media-buy、signals、governance、creative、brand）に適用 — Accounts Protocol の面は共有。`created`、`updated`、`unchanged` の結果で存在。`failed` の結果では省略。スコープイントロスペクションをサポートするベンダーエージェントはこれを設定すべき（SHOULD）。`attestation_verifier` 標準スコープを主張する media-buy sales agent は設定しなければならない（MUST）。不在は、ベンダーエージェントがイントロスペクション可能なスコープを宣伝しないことを意味する。呼び出し元は不在からアクセスを推論してはならない（MUST NOT）。完全な形状は [Caller authorization](/docs/accounts/overview#caller-authorization) を参照。 |

<h3 id="account-status">
  アカウントステータス
</h3>

| ステータス              | 意味             | 次のステップ                                                                                    |
| ------------------ | -------------- | ----------------------------------------------------------------------------------------- |
| `active`           | 使用準備完了         | プロトコル操作で [アカウント参照](/docs/building/by-layer/L2/accounts-and-agents#account-references) を使用 |
| `pending_approval` | セラーがレビュー中      | 与信または法的プロセスを完了するために人間が `setup.url` にアクセスする必要がある場合があります。更新確認のため `list_accounts` をポーリング。    |
| `rejected`         | セラーがリクエストを拒否   | `warnings` の拒否理由を確認し、調整して再試行するかセラーに連絡                                                     |
| `payment_required` | 与信限度額超過または残高不足 | 資金追加または与信限度額引き上げ。他のアカウントに支出を振り分ける。                                                        |
| `suspended`        | アクティブだったが現在停止中 | セラーに連絡して解決                                                                                |
| `closed`           | アクティブだったが現在終了  | --                                                                                        |

### 非同期通知

`push_notification_config` が提供され、セラーが `pending_approval` を返した場合、アカウントステータスが変更されると（例: 承認 → `active`、拒否 → `rejected`）、セラーはWebhook通知を送信します。

プロビジョニングリクエストでは、通知ペイロードに `(brand, operator)` の自然キーが含まれるため、バイヤーは元の同期リクエストと関連付けられます。セラーがセラー割り当ての `account_id` も返す場合、通知は便宜ハンドルとしてそれを含みます。バイヤーは後続の呼び出しについて依然セラーの宣言されたアカウント参照モデルに従います。

```json theme={null}
{
  "brand": { "domain": "nova-brands.com", "brand_id": "glow" },
  "operator": "pinnacle-media.com",
  "status": "active",
  "account_id": "acc_glow_001"
}
```

バイヤーが `push_notification_config` を提供しなかった場合、ステータス変更を確認するために [`list_accounts`](/docs/accounts/tasks/list_accounts) をポーリングします。

## 2つのモード: プロビジョニング vs. 設定更新

各アカウントごとのエントリは 2 つのキー形状の 1 つを使い、両方を使うことはありません:

* **プロビジョニングモード** — エントリルートにフラットな `brand` + `operator` + `billing`。セラーはアカウントをプロビジョニングまたはアップサートします。バイヤー宣言アカウント（`require_operator_auth: false`）に使用。これは AdCP 3.0 が出荷した形状です。セラーは `account_id` をエコーしてもよい（MAY）が、自然キーの `AccountRef` は後続の呼び出しで有効なままです。
* **設定更新モード** — エントリルートに `account`（[AccountRef](/docs/building/by-layer/L2/accounts-and-agents#account-references)）、`brand`/`operator`/`billing` は不在。セラーはアカウントの設定可能な状態を更新します — プロビジョニングの副作用なし。セラーがこのタスクを通じて設定更新を公開する場合のアカウント ID 名前空間にのみ使用。上流管理のアカウントは `list_accounts` で探索し、セラー定義のアカウント ID はアウトオブバンドで供給されます。バイヤー宣言アカウントセラーも、以前にプロビジョニングしたアカウントに対する設定更新にこのモードを受け入れてもよい（MAY）。

スキーマは `oneOf` で排他性を強制します — 同じエントリに両方の形状を送ることは検証エラーです。設定更新モードを実装しないセラーは `account` でキーされたエントリを `UNSUPPORTED_PROVISIONING` で拒否します。`sync_accounts` を通じてプロビジョニングしないセラー（アカウント ID 名前空間を含む）は、同じコードで自然キープロビジョニングエントリを拒否します。

## アカウントレベルの Webhook サブスクリプション

`notification_configs[]` は、ライフサイクルが単一のメディアバイより長く続く通知向けのアカウントレベル Webhook サブスクライバーを運びます — `creative.status_changed`、`creative.purged`、ホールセールフィード変更 Webhook（`product.*`、`signal.*`、`wholesale_feed.bulk_change`）、および `notification-type.json` にそれらのイベントタイプが追加された後の将来のアカウントアンカーリソースイベント。

これはアカウントオブジェクトのライフサイクルイベントストリームではありません。今日 `account.created`、`account.updated`、`account.status_changed`、`account.closed` の通知タイプはありません。アカウントステータスの変更は [`list_accounts`](/docs/accounts/tasks/list_accounts) をポーリングするか、`sync_accounts` プロビジョニングリクエストの非同期結果についてはこのタスクの `push_notification_config` を通じて観測します。

これらのイベントタイプでは、「ホールセールフィード」はセラーの購入可能なホールセールプロダクトと `get_products` または `get_signals` が返すシグナルフィードを意味します。`sync_catalogs` が管理するバイヤー提供のフィードではありません。

**両方**のプロビジョニングと設定更新モードで許可されます。宣言的セマンティクス:

* `notification_configs` を省略すると、アカウントの既存のサブスクライバーを変更しません。
* `notification_configs: []` を送ると、そのアカウントのすべてのサブスクライバーを削除します。
* 非空の配列を送ると、アカウントの現在のセットを提出されたセットで置き換えます。

1 つのアカウント内で、`subscriber_id` は安定した論理キーです。既存の `(account_id, subscriber_id)` を異なる `url`、`event_types`、`authentication`、`active` 値で再送すると、重複を作るのではなくそのサブスクライバーのアクティブ設定を置き換えます。セラーは提出された配列を永続状態とマージしてはなりません（MUST NOT）: `subscriber_id` が送信配列に現れない永続化されたサブスクライバーは削除されます。一時停止されたエントリ（`active: false`）は同じ置き換えセマンティクスの対象です。一時停止されたサブスクリプションを保持するには、送信配列に `active: false` で再度含めます。同じ提出配列内の重複した `subscriber_id` 値は無効です。置き換えはアカウントスコープです。同じ `subscriber_id` は別のアカウントで再利用してもよい（MAY）。

提出された置き換えセットの任意のエントリが検証またはアクティベーション証明に失敗した場合、セラーはそのアカウントエントリを `action: "failed"` で拒否し、アカウントの以前の `notification_configs[]` セットを変更しないままにします。セラーは置き換えセットを部分適用して失敗したサブスクライバーのみを黙って落としてはなりません（MUST NOT）。

各エントリは次を持ちます:

* `subscriber_id` — バイヤー供給の識別子、アカウント内で一意。マルチサブスクライバーアカウントがエンドポイントでルーティングできるよう、すべての発火でエコーされる
* `url` — HTTPS エンドポイント URL。セラーは、新規または変更されたアクティブサブスクライバーをアクティブとして扱う前に、エンドポイントアクティベーションチャレンジまたは同等の制御証明を完了しなければならない（MUST）。
* `event_types[]` — サブスクライバーが望むタイプ。アカウントアンカータイプのみ許可（今日: `creative.status_changed`、`creative.purged`、`product.created`、`product.updated`、`product.priced`、`product.removed`、`signal.created`、`signal.updated`、`signal.priced`、`signal.removed`、`wholesale_feed.bulk_change`）。セラーは任意のメディアバイアンカータイプ（`scheduled`、`final`、`delayed`、`adjusted`、`impairment`）と `account.status_changed` のような未定義のアカウントライフサイクル名を、`accounts[].errors[]` の `INVALID_REQUEST` または `VALIDATION_ERROR` でアカウントごとの検証失敗として拒否しなければならず（MUST）、`error.field` は無効な `event_types` エントリを指さなければならない（MUST）。
* `authentication`（オプション）— レガシー Bearer または HMAC-SHA256。デフォルトの RFC 9421 Webhook プロファイルを使うには省略。存在する場合、`push_notification_config.authentication` と同じ署名付き登録のダウングレード耐性ルールが適用されます。クレデンシャルは書き込み専用 — セラーは読み取り時に省略します。
* `active`（デフォルト `true`）— 登録を削除せずにサブスクライバーを一時停止するには `false` を設定。セラーは `active: false` の間アウトバウンド証明チャレンジのみスキップしてもよい（MAY）。書き込み時に HTTPS パース、ホスト名正規化、予約範囲拒否を依然強制しなければならない（MUST）。一時停止されたサブスクライバーは再アクティベートされるまで発火を受け取ってはならない（MUST NOT）。再アクティベーションは、現在の有効な証明がない任意のタプルについて、接続ピン留め付きの完全な SSRF 検証と制御証明を繰り返さなければならない（MUST）。

### エンドポイントの制御証明

エントリを `active: true` として永続化またはエコーする前に、セラーは URL を検証し、[Webhook URL validation](/docs/building/by-layer/L1/security#webhook-url-validation-ssrf) の SSRF ルールを適用し、レシーバーがエンドポイントを制御することを証明しなければなりません（MUST）。

証明は、タプル `(account_id, subscriber_id, normalized url, authentication mode/credential binding, normalized event_types)` について現在の有効な証明がないときに必要です。サブスクライバー ID、正規化 URL、認証モード/クレデンシャルバインディング、`event_types[]` を変更すると、新しいセットがアクティブになる前に新しい証明が必要です。チャレンジ POST 自体は、候補設定がレガシー配信認証を選択しても、セラーの RFC 9421 Webhook プロファイル鍵で署名されなければなりません（MUST）。新しい署名者は `adcp_use: "request-signing"` を使用。非推奨の `webhook-signing` 鍵は互換期間中も受け入れられます。レシーバーは RFC 9421 署名を検証しなければならず（MUST）、`seller_agent_url`、`delivery_auth`、`event_types` が保留中の登録に一致しない限りチャレンジを拒否しなければなりません（MUST）。セラーは独自の証明有効期限ポリシーで再チャレンジしてもよい（MAY）。

標準チャレンジは、`type`、`challenge`、`account_id`、`subscriber_id`、`seller_agent_url`、`delivery_auth`、`event_types` を含む JSON ボディを持つ候補 `url` への HTTPS POST です。正準スキーマは [`webhook-challenge.json`](https://adcontextprotocol.org/schemas/v3/core/webhook-challenge.json) と [`webhook-challenge-response.json`](https://adcontextprotocol.org/schemas/v3/core/webhook-challenge-response.json) です。

```json theme={null}
{
  "type": "webhook.challenge",
  "challenge": "example-challenge-token-000000000000",
  "account_id": "acct_123",
  "subscriber_id": "buyer-primary",
  "seller_agent_url": "https://seller.example/adcp",
  "delivery_auth": { "mode": "rfc9421" },
  "event_types": ["creative.status_changed"]
}
```

レシーバーは、正確に 1 つのエコーフィールドを含む JSON ボディで HTTP `2xx` を返して制御を証明します:

```json theme={null}
{ "challenge": "example-challenge-token-000000000000" }
```

セラーは後方互換エイリアスも受け入れなければなりません（MUST）:

```json theme={null}
{ "token": "example-challenge-token-000000000000" }
```

チャレンジ値は暗号学的にランダムで、単一使用で、登録タプルにスコープされなければなりません（MUST）。失敗、非 `2xx`、不正、不一致、タイムアウトのチャレンジは証明失敗を意味します。セラーは SSRF 検証と同じアウトバウンドフェッチ上限（10 秒接続、10 秒読み取り）を使うべきで（SHOULD）、`sync_accounts` のクリティカルパスで最大 1 回の初回チャレンジ POST を行うべきです（SHOULD）。セラーは、同じチャレンジ値を使いリクエスト予算内で完了する場合、返す前に 1 回の一時的ネットワーク失敗をリトライしてもよい（MAY）。そうでなければバイヤーは `sync_accounts` を再送してリトライします。

証明失敗時、セラーは `action: "failed"`、`errors[].code: "VALIDATION_ERROR"`（不正 URL には `INVALID_REQUEST`）、`accounts[i].notification_configs[j].url` を指す `error.field` を持つアカウントごとの失敗を返します。以前の永続化されたサブスクライバーセットは変更されません。`dry_run: true` はネットワークチャレンジを送ってはなりません（MUST NOT）。構造検証と何が証明を必要とするかのみを報告できます。

例 — アカウント ID 名前空間アカウントにバイヤー側エンドポイントと監査バスを登録:

```json theme={null}
{
  "idempotency_key": "f2c4b7d9-6789-49bc-defa-2345678901bc",
  "accounts": [
    {
      "account": { "account_id": "acc_acme_pinnacle" },
      "notification_configs": [
        {
          "subscriber_id": "buyer-primary",
          "url": "https://buyer.example/webhooks/adcp/creative",
          "event_types": ["creative.status_changed", "creative.purged"],
          "active": true
        },
        {
          "subscriber_id": "audit-bus",
          "url": "https://audit.buyer.example/adcp/ingest",
          "event_types": ["creative.status_changed", "creative.purged"],
          "active": true
        }
      ]
    }
  ]
}
```

例 — ホールセールプロダクトとシグナル変更のためのホールセールフィードミラーサブスクライバーを登録:

```json theme={null}
{
  "idempotency_key": "a8af8cf1-89bd-41f3-b27d-7ee7e9f8d2e4",
  "accounts": [
    {
      "account": { "account_id": "acc_acme_pinnacle" },
      "notification_configs": [
        {
          "subscriber_id": "wholesale-feed-sync",
          "url": "https://buyer.example/webhooks/adcp/wholesale-feed",
          "event_types": [
            "product.created",
            "product.updated",
            "product.priced",
            "product.removed",
            "signal.created",
            "signal.updated",
            "signal.priced",
            "signal.removed",
            "wholesale_feed.bulk_change"
          ],
          "active": true
        }
      ]
    }
  ]
}
```

[`sync_governance`](/docs/accounts/tasks/sync_governance) で登録されたガバナンスエージェントは、これらの Webhook に暗黙的にサブスクライブ**されません**。ガバナンスエージェントもクリエイティブライフサイクルの発火を受け取るべき場合、その URL を別個の `notification_configs[]` エントリとして登録します — 明示的、監査可能、独自の `event_types[]` フィルター付き。

適用された状態は [`list_accounts`](/docs/accounts/tasks/list_accounts) で検証します — レスポンスはクレデンシャルを秘匿した現在の永続化された `notification_configs[]` をアカウントごとに運びます。`sync_accounts` も、リクエストが `notification_configs` を含んだか、任意の永続化されたサブスクライバーがすでに存在する場合、`created`、`updated`、`unchanged` の結果で現在のサニタイズされたセットをエコーします。

ホールセールフィード通知は、別個のサブスクリプションタスクではなくここで登録されます。Webhook ボディは [`wholesale-feed-webhook.json`](https://adcontextprotocol.org/schemas/v3/core/wholesale-feed-webhook.json) です: 変更されたプロダクト、シグナル、またはバルク変更サマリーに加え、変更後の `wholesale_feed_version` を運びます。セラーは各 Webhook を発行する前に、対応するホールセール読み取りが使うのと同じサブスクライバーごとの認可とスコープ述語を適用しなければなりません（MUST）。レシーバーはペイロードをローカルミラーに適用してもよい（MAY）。逃した/信頼できないプッシュの修復と、支出や権限をバインドする前には `if_wholesale_feed_version` 付きの `get_products` / `get_signals` を使います。ケイパビリティ宣言とイベントセマンティクスは [wholesale\_feed\_webhooks](/docs/protocol/get_adcp_capabilities#wholesale_feed_webhooks) を参照。

## 一般的なシナリオ

### 複数のブランドを同期する代理店

<CodeGroup>
  ```javascript JavaScript theme={null}
  import { testAgent } from "@adcp/sdk/testing";
  import { SyncAccountsResponseSchema } from "@adcp/sdk";

  const result = await testAgent.syncAccounts({
    accounts: [
      {
        brand: { domain: "nova-brands.com", brand_id: "spark" },
        operator: "pinnacle-media.com",
        billing: "operator",
      },
      {
        brand: { domain: "nova-brands.com", brand_id: "glow" },
        operator: "pinnacle-media.com",
        billing: "operator",
      },
    ],
  });

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

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

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

  for (const account of validated.accounts) {
    if (account.status === "active") {
      console.log(`Ready: ${account.brand.domain}/${account.brand.brand_id} → ${account.status}`);
    } else if (account.status === "pending_approval") {
      console.log(`Setup required for ${account.brand.brand_id}: ${account.setup?.url}`);
      // アクティブになるまで list_accounts をポーリング
    }
  }
  ```

  ```python Python theme={null}
  import asyncio
  from adcp.testing import test_agent

  async def main():
      result = await test_agent.simple.sync_accounts(
          accounts=[
              {
                  "brand": {"domain": "nova-brands.com", "brand_id": "spark"},
                  "operator": "pinnacle-media.com",
                  "billing": "operator",
              },
              {
                  "brand": {"domain": "nova-brands.com", "brand_id": "glow"},
                  "operator": "pinnacle-media.com",
                  "billing": "operator",
              },
          ],
      )

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

      for account in result.accounts:
          if account.status == 'active':
              print(f"Ready: {account.brand['domain']}/{account.brand.get('brand_id')} → {account.status}")
          elif account.status == 'pending_approval':
              print(f"Setup required for {account.brand.get('brand_id')}: {account.setup.url}")
              # アクティブになるまで list_accounts をポーリング

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

### ブランドによる直接購入

<CodeGroup>
  ```javascript JavaScript theme={null}
  import { testAgent } from "@adcp/sdk/testing";
  import { SyncAccountsResponseSchema } from "@adcp/sdk";

  const result = await testAgent.syncAccounts({
    accounts: [
      {
        brand: { domain: "acme-corp.com" },
        operator: "acme-corp.com",
        billing: "operator",
      },
    ],
  });

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

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

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

  const account = validated.accounts[0];
  if (account.status === "active") {
    console.log(`Ready: ${account.brand.domain} — ${account.status}`);
  } else if (account.status === "pending_approval") {
    console.log(`Setup required: ${account.setup?.url}`);
    // アクティブになるまで list_accounts をポーリング
  }
  ```

  ```python Python theme={null}
  import asyncio
  from adcp.testing import test_agent

  async def main():
      result = await test_agent.simple.sync_accounts(
          accounts=[
              {
                  "brand": {"domain": "acme-corp.com"},
                  "operator": "acme-corp.com",
                  "billing": "operator",
              },
          ],
      )

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

      account = result.accounts[0]
      if account.status == 'active':
          print(f"Ready: {account.brand['domain']} — {account.status}")
      elif account.status == 'pending_approval':
          print(f"Setup required: {account.setup.url}")
          # アクティブになるまで list_accounts をポーリング

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

### 拒否の処理

セラーがリクエストを拒否した場合、アカウントエントリは `status: "rejected"` を持ちます。

<CodeGroup>
  ```javascript JavaScript theme={null}
  import { testAgent } from "@adcp/sdk/testing";
  import { SyncAccountsResponseSchema } from "@adcp/sdk";

  const result = await testAgent.syncAccounts({
    accounts: [
      {
        brand: { domain: "acme-corp.com", brand_id: "clearance" },
        operator: "acme-corp.com",
      },
    ],
  });

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

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

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

  for (const account of validated.accounts) {
    if (account.status === "rejected") {
      console.log("Account request was rejected");
      if (account.warnings?.length) {
        console.log(`Reason: ${account.warnings.join(", ")}`);
      }
    }
  }
  ```

  ```python Python theme={null}
  import asyncio
  from adcp.testing import test_agent

  async def main():
      result = await test_agent.simple.sync_accounts(
          accounts=[
              {
                  "brand": {"domain": "acme-corp.com", "brand_id": "clearance"},
                  "operator": "acme-corp.com",
              },
          ],
      )

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

      for account in result.accounts:
          if account.status == 'rejected':
              print("Account request was rejected")
              warnings = getattr(account, 'warnings', None)
              if warnings:
                  print(f"Reason: {', '.join(warnings)}")

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

## エラーハンドリング

| エラーコード                            | 説明                                                                                                                                                                   | 解決策                                                                                                                          |
| --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `ACCOUNT_NOT_FOUND`               | 参照されたアカウントが存在しないか、アクセスできない                                                                                                                                           | `account_id` を確認するか、再同期する                                                                                                    |
| `BILLING_NOT_SUPPORTED`           | セラー全体のケイパビリティゲート（`supported_billing` が値を含まない）またはアカウント関係ごとのゲート。[Billing and Account Setup](/docs/building/by-layer/L3/error-handling#billing-and-account-setup)を参照    | `supported_billing` の `get_adcp_capabilities` を確認し、調整または `billing` を省略。ケイパビリティ vs アカウントスコープを区別するには `error.details.scope` を検査 |
| `BILLING_NOT_PERMITTED_FOR_AGENT` | セラー全体のケイパビリティは値を受け入れるが、呼び出しバイヤーエージェントの商業関係が許可しない（例: パススルー専用 — 支払い関係なし）。[バイヤーエージェントのアイデンティティ](/docs/building/by-layer/L2/accounts-and-agents#buyer-agent-identity)を参照 | 存在する場合は `error.details.suggested_billing`（通常 `operator`）でリトライ。不在の場合は人間に表面化 — エージェントは自身の商業関係を拡張できない                           |
| `PAYMENT_TERMS_NOT_SUPPORTED`     | セラーがリクエストされた支払い条件を受け入れない                                                                                                                                             | セラーのデフォルトを受け入れるため `payment_terms` を省略するか、オフラインで交渉                                                                            |
| `ACCOUNT_PAYMENT_REQUIRED`        | アカウントに支払いが必要な未払い残高がある                                                                                                                                                | 未払い残高を解決するか、別のアカウントに振り分ける                                                                                                    |
| `ACCOUNT_SUSPENDED`               | アカウントが停止されている                                                                                                                                                        | セラーに連絡して解決                                                                                                                   |
| `BRAND_REQUIRED`                  | ブランド参照なしで請求可能な操作が試みられた                                                                                                                                               | リクエストに `brand` を含める                                                                                                          |

## 次のステップ

* [list\_accounts](/docs/accounts/tasks/list_accounts) -- 保留中のアカウントのステータス変更をポーリング
* [sync\_governance](/docs/accounts/tasks/sync_governance) -- ガバナンスエージェントをアカウントに同期
* [アカウントとエージェント](/docs/building/by-layer/L2/accounts-and-agents) -- 請求モデル、信頼モデル、認可オペレーター
* [ブランドプロトコル](/docs/brand-protocol/brand-json) -- セラーエージェントが `brand.domain` からブランドアイデンティティを解決する方法
* [get\_adcp\_capabilities](/docs/protocol/get_adcp_capabilities) -- アカウントを同期する前に `supported_billing` と `require_operator_auth` を確認
