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

# adagents.json 技術仕様

> adagents.json はパブリッシャーが広告プロパティを宣言し、セールスエージェントに在庫販売を認可する AdCP のファイル仕様。

`adagents.json` ファイルは、パブリッシャーがプロパティを宣言し、セールスエージェントを認可するための標準的な手段を提供します。これは Property Governance の土台であり — どのプロパティが存在し、誰がそれらを販売できるかを定義します。

### 統一宣言モデル

`adagents.json` は、**プロパティ認可**と**シグナルデータプロバイダー**登録の両方の宣言メカニズムとして機能します。`/.well-known/adagents.json` の単一ファイルが、`properties` と `signals` のトップレベルフィールドの両方を同時に宣言できます。

```json theme={null}
{
  "version": "1.0",
  "properties": [
    {
      "domain": "publisher.example.com",
      "agents": [
        { "agent_url": "https://ads.publisher.example.com", "relationship": "direct" }
      ]
    }
  ],
  "signals": [
    {
      "catalog_url": "https://signals.publisher.example.com/catalog.json",
      "relationship": "direct",
      "description": "First-party audience signals from publisher.example.com"
    }
  ]
}
```

この結合モデルは、ファーストパーティデータを持つパブリッシャーで一般的です — 同じドメインがセールスエージェントを認可し（`properties` 経由）、公開されたシグナル定義を宣言します（`signals` 経由）。2 つの名前空間は独立しています: プロパティ販売の認可はシグナルアクセスを付与せず、シグナル登録はプロパティ認可を意味しません。

シグナル側のドキュメントについては [シグナルデータプロバイダー](/docs/signals/data-providers) を参照。

パブリッシャー認可をオペレーターの `brand.json` アイデンティティと署名鍵ディスカバリーとペアリングするセルサイドの決定木については、[セラーセットアップ](/docs/brand-protocol/seller-setup) を参照。

<Tip>
  **[AdAgents.json Builder](https://agenticadvertising.org/adagents/builder)** - 既存ファイルの検証やガイド付きでの新規作成に利用できます
</Tip>

## Why `adagents.json` instead of `ads.txt`

`ads.txt` はより狭い問いに答えます: このセラーはパブリッシャーのリストに存在するか、関係は `DIRECT` か `RESELLER` とラベル付けされているか？

それは有用ですが、多くの現代的なパブリッシャー販売モデルにとって平坦すぎます。バイヤーに次を伝えません。

* どのプロパティがカバーされているか
* どのプレースメントがカバーされているか
* パスが直接、委任、ネットワーク仲介のいずれか
* 認可が国限定または時間限定か
* ネットワーク管理のスロットがパブリッシャー管理のプレミアムプレースメントと同じものか

`adagents.json` はその構造を運ぶよう設計されています。パブリッシャーがプロパティアイデンティティ、プレースメントアイデンティティ、委任タイプ、スコープ付き認可、パブリッシャー定義のグルーピングタグを 1 か所で宣言できます。

| Question                            | `ads.txt` | `adagents.json`           |
| ----------------------------------- | --------- | ------------------------- |
| このセラーはそもそも宣言されているか？                 | Yes       | Yes                       |
| どのプロパティがカバーされているか？                  | No        | Yes                       |
| どのプレースメントがカバーされているか？                | No        | Yes                       |
| パブリッシャーはインベントリを管理されたバケットにグループ化できるか？ | No        | Yes（`placement_tags` 経由）  |
| 認可は国や時間ウィンドウで変わりうるか？                | No        | Yes                       |
| パスを直接、委任、ネットワーク仲介として記述できるか？         | 非常に弱く     | Yes（`delegation_type` 経由） |

より高レベルのフレーミングと並列比較の例については、[Why adagents.json is more expressive than ads.txt](https://agenticadvertising.org/perspectives/adagents-json-vs-ads-txt) を参照。

### Where does sellers.json fit?

プログラマティックでは、`sellers.json` はセラー/エクスチェンジによってホストされ、彼らが代表するパブリッシャーを宣言します。AdCP は、別個のファイルの代わりに `brand.json` を通じてこれを処理します。オペレーターは、`relationship` フィールドを使って [`brand.json`](/docs/brand-protocol/brand-json) でプロパティを宣言します。ファーストパーティインベントリについては、オペレーターは `relationship: "owned"` を使えます。委任またはネットワークのセルサイドパスについては、`relationship` は `delegation_type` と同じ値を使います: `direct`、`delegated`、または `ad_network`。これにより、同じ双方向検証パターンが作られます。

| Programmatic                                         | AdCP equivalent                                | Purpose                         |
| ---------------------------------------------------- | ---------------------------------------------- | ------------------------------- |
| `ads.txt`（パブリッシャー）                                   | `delegation_type` を持つ `adagents.json`（パブリッシャー） | 「これらのエージェントは認可されている、これが関係」      |
| `relationship` を持つ `brand.json` の properties（オペレーター） |                                                | 「私はこれらのパブリッシャーのために販売する、これがその方法」 |

委任またはネットワークパスについては、両側が合意しなければなりません — `delegation_type` と `relationship` の値は一致すべきです。ファーストパーティインベントリについては、`relationship: "owned"` はインラインの所有権宣言であり、一致する `delegation_type` 値はありません。実際にこれがどう機能するかについては [アドネットワーク](/docs/sponsored-intelligence/networks) を参照。

<Note>
  フィールドは adagents.json では `delegation_type`、brand.json では `relationship` と呼ばれます。名前が異なるのは、同じ商業的取り決めを異なる視点から記述するためです — パブリッシャーが権限を委任し（`delegation_type`）、オペレーターがプロパティへの関係を宣言します（`relationship`）。委任/ネットワークの値は一致します（`direct`、`delegated`、`ad_network`）。`owned` は brand.json の relationship 値のみです。
</Note>

## 配置場所

パブリッシャーは `adagents.json` を次の場所に配置する必要があります:

```
https://example.com/.well-known/adagents.json
```

[RFC 8615](https://datatracker.ietf.org/doc/html/rfc8615) の well-known URI に従うことで、一貫した発見性を確保します。

<Note>
  パブリッシャーのオリジンが HTTP リダイレクトでホスト名を正規化する場合、最終的に解決された URL にもファイルをデプロイします。例えば、`https://example.com/.well-known/adagents.json` が `https://www.example.com/.well-known/adagents.json` にリダイレクトする場合、`www` の URL は `200` レスポンスで JSON ファイルを提供しなければなりません。

  `404` で終わるリダイレクトチェーンは、正規ホストでファイルが欠けていることを意味します。中間の `301` や `302` だけでなく、終端のステータスと解決された URL をトラブルシューティングしてください。
</Note>

## 基本構造

ファイルは UTF-8 の有効な JSON で、HTTP 200 を返す必要があります。

```json theme={null}
{
  "$schema": "https://adcontextprotocol.org/schemas/v3/adagents.json",
  "contact": {
    "name": "Example Publisher Ad Operations",
    "email": "adops@example.com",
    "domain": "example.com",
    "seller_id": "pub-example-12345",
    "tag_id": "67890"
  },
  "properties": [
    {
      "property_id": "example_site",
      "property_type": "website",
      "name": "Example Site",
      "identifiers": [
        {"type": "domain", "value": "example.com"}
      ]
    }
  ],
  "authorized_agents": [
    {
      "url": "https://agent.example.com",
      "authorized_for": "Official sales agent",
      "authorization_type": "property_ids",
      "property_ids": ["example_site"]
    }
  ],
  "last_updated": "2025-01-10T12:00:00Z"
}
```

## スキーマフィールド

**`$schema`** *(任意)*: 検証用の JSON Schema 参照

**`contact`** *(任意)*: ファイル管理主体の連絡先

* **`name`** *(必須)*: 管理主体名（パブリッシャーまたは第三者）
* **`email`** *(任意)*: 問い合わせ先メール
* **`domain`** *(任意)*: 管理主体のドメイン
* **`seller_id`** *(任意)*: IAB Tech Lab sellers.json の Seller ID
* **`tag_id`** *(任意)*: TAG Certified Against Fraud ID
* **`privacy_policy_url`** *(任意)*: 消費者同意フロー用のプライバシーポリシー URL

**`catalog_etag`** *(任意)*: このファイルの公開カタログ部分の不透明なキャッシュ/バージョントークン

* パブリッシャーは、`properties`、`collections`、`placements`、`formats`、`signals`、またはそれらのタグメタデータが変わるたびにこれを変更すべきです（SHOULD）
* バイヤー SDK は、解決された参照を URL + `catalog_etag` でキャッシュし、値が変わったときにカタログ参照を再解決すべきです（SHOULD）
* 存在しない場合、バイヤーは `ETag`/`Last-Modified` などの HTTP バリデーター、次に上限付き TTL にフォールバックします

**`properties`** *(任意)*: このファイルで扱うプロパティの配列（正規定義）

* **`supported_channels`** *(任意)*: このプロパティがサポートする広告チャネルの配列（例: `["display", "olv", "social"]`）。[Media Channel Taxonomy](/docs/reference/media-channel-taxonomy) を参照。

**`collections`** *(任意)*: このパブリッシャーが制作または配信するコレクション

* プロダクトは `publisher_domain` と `collection_ids` を持つ `collections` セレクターを通じてこれらを参照します
* 認可を特定のシリーズ、ポッドキャスト、ストリーム、または定期的なコンテンツプログラムにスコープする必要がある場合に有用

**`placements`** *(任意)*: このファイル内のプロパティの正規プレースメント定義

* プロダクトは `placements` を宣言する際にこれらの `placement_id` 値を再利用すべきです（SHOULD）
* 登録済み `placement_id` を再利用することは、プロダクトが同じセマンティックプレースメントを指していることを意味し、同じ ID で別のものを発明していないことを意味します
* プレースメント定義には、プロパティリンクのための `tags`、`property_ids` または `property_tags`、`channels`、クリエイティブサポートのための `format_options` を含められます
* `adagents.json` のプレースメントは定義上公開です。セラー非公開のプレースメント ID、source/origin フィールド、配信システムマッピングをこのファイルに公開しないでください
* 認可エントリはスコープを特定の `placement_ids` に狭められます
* 認可エントリは、`programmatic`、`direct_only`、`managed_by_riverline` などの管理されたプレースメントグルーピングのために `placement_tags` も使えます
* 「このエージェント経由ではホームページネイティブフィードのみ利用可能」や「プレロールのみ」のような区別を表現するのに有用

**`tags`** *(任意)*: 人間可読なコンテキストを提供し効率的なグルーピングを可能にするタグメタデータ

**`placement_tags`** *(任意)*: パブリッシャー定義のプレースメントタグのメタデータ

* `placements[*].tags` と `authorized_agents[*].placement_tags` で使われるプレースメントタグ値の人間可読な定義を提供します
* これらはパブリッシャーローカルな概念であり、グローバルタクソノミーではありません

### Public placement catalog

`placements[]` 配列はパブリッシャーの公開プレースメントカタログです。プロダクトと認可ルールが参照できる安定したセマンティックなプレースメント ID を定義します。バイヤーは、プロダクトが何を提供するかを理解するために、生のアドサーバー広告ユニットパス、配信プレースメント ID、ビデオアドサーバーゾーン、またはその他のセラー内部の配信識別子を解釈する必要があるべきではありません。

プレースメント、フォーマット、コレクション、プロパティのカタログ、または公開された `signals[]` 定義を公開するパブリッシャーは、`catalog_etag` を公開し、それらのエントリが変わるたびに更新すべきです。これにより、バイヤー SDK は、パブリッシャーのデプロイ後に同じ `{publisher_domain, placement_id}` や `{publisher_domain, format_option_id}` を黙って異なるメタデータに解決することなく、カタログルックアップをキャッシュできます。

最低限、公開プレースメントは次を記述すべきです。

* 安定した `placement_id`
* `name` と `description`
* それが実行できる `property_ids` または `property_tags`
* サポートされる `format_options`（パブリッシャー所有フォーマットと正準フォーマットを参照できる）
* 任意の `channels`

プレースメントのフォーマットサポートは新しい 3.1 のカタログ機能であり、3.1+ の正準フォーマットオプションモデルのみを使います。

* `format_options[]` は、同じファイルのトップレベル `formats[]` の宣言を `format_option_id` で参照できます。それらのトップレベル宣言は、パブリッシャー所有のカスタムフォーマットまたは狭められた正準フォーマットです。
* `format_options[]` は、プレースメント固有の狭めが再利用可能なトップレベルフォーマットエントリに値しない場合、インラインの正準 `ProductFormatDeclaration` を運ぶこともできます。

正準アンカーは `format_kind` です。`{ "format_option_id": "..." }` のみを運ぶプレースメントエントリは、その ID を同じファイルのトップレベル `formats[]` 宣言に解決し、その `format_kind` を読むことで正準フォーマットを継承します。このファイルの外では、パブリッシャー宣言のフォーマットオプションのバイヤー向け `FormatOptionRef` は `{ "scope": "publisher", "publisher_domain": "...", "format_option_id": "..." }` を使います。

プレースメントカタログのフォーマットは、公開プレースメントが何をサポートできるかを記述します。プロダクトが後でそのプレースメントを参照する場合、プロダクトレベルの `format_ids` または `format_options` が購入可能なクリエイティブコントラクトのままです。プレースメントの `format_options` は特定のプレースメントについてそのセットを狭めます。カタログのプレースメントとプロダクトの宣言が食い違う場合、バイヤーは交差を使い、カタログのみのフォーマットをプロダクトに受け入れられたものとして扱うべきではありません。

```json theme={null}
{
  "catalog_etag": "daily-pulse-2026-05-25",
  "formats": [
    {
      "format_kind": "html5",
      "format_option_id": "publisher_takeover_html5",
      "display_name": "Publisher takeover HTML5",
      "params": {
        "width": 970,
        "height": 250,
        "max_file_size_kb": 200
      }
    }
  ],
  "placements": [
    {
      "placement_id": "homepage_takeover",
      "name": "Homepage takeover",
      "description": "High-impact homepage sponsorship across the main article rail and top video module.",
      "property_ids": ["daily_pulse"],
      "channels": ["display", "olv"],
      "format_options": [
        { "format_option_id": "publisher_takeover_html5" },
        {
          "format_kind": "image",
          "params": {
            "width": 300,
            "height": 250,
            "image_formats": ["jpg", "png"],
            "max_file_size_kb": 150
          }
        }
      ]
    }
  ]
}
```

`adagents.json` は公開であるため、運用インベントリの内部を公開する場所ではありません。source/origin（`synced` 対 synthetic）、生のアドサーバー ID、配信マッピング、セラー非公開のプレースメントグルーピングは、セラーの内部インベントリレジストリに保持してください。公開プレースメントカタログは、パブリッシャーが発見可能にしたいバイヤーが理解できるインベントリのみを記述すべきです。

### Product targetability

`adagents.json` は、プレースメントがプロダクトでターゲット可能かどうかを決定しません。安定した公開プレースメント ID とそのバイヤー理解可能なセマンティクスを公開するだけです。

セールスエージェントは、公開プレースメントがバイヤー選択可能か、単にプロダクト構成の一部かを、プロダクトごとに決定します。その決定は、必要なときに、パブリッシャーの `adagents.json` ではなくセールスエージェントの `get_products` プロダクトプレースメントオブジェクトで公開されます。

プロダクトがセラー非公開の配信構成に依存する場合、その構成をプロダクトの文章で記述し、基礎となるプレースメント ID をセラーシステムに保持してください。非公開のプレースメント ID を `adagents.json` や `get_products` に公開しないでください。

### Internal mapping

パブリッシャーは依然として公開プレースメントを配信システムにマッピングする必要があり、配信システムに適切なセマンティックオブジェクトがない場合、合成的な内部グルーピングが必要になる場合があります。そのマッピングは実装の詳細であり、公開プロトコル状態ではありません。

一般的な内部ケース:

* 複数の synced プレースメントのグルーピング
* 複数の広告ユニットまたはゾーンのグルーピング
* 広告ユニットをバイヤー理解可能なプレースメントとして公開
* 曖昧な `1x1`、fluid、native、out-of-page、または video オブジェクトを実際にレンダリングするフォーマットにマッピング
* 生の配信 ID からプロダクトを解放しながら戦略的な不透明性を保持

これらの内部マッピングは公開 `placements[]` エントリを生成できますが、マッピングの詳細自体は `adagents.json` の外に留まります。

**`authorized_agents`** *(必須)*: 認可されたセールスエージェントの配列。AdCP を採用していないプラットフォームのために `formats`/`properties`/`placements`（通常は `catalog_etag` 付き）を公開する**カタログのみのコミュニティミラー** — 認可するセールスエージェントがないファイル — では空（`[]`）でもかまいません（MAY。[コミュニティミラーライフサイクル](#community-mirror-lifecycle)を参照）。空の配列は**セールス認可なし**を主張します: バリデーターはそれを deny-all、authorize-all、または失効として読んではならず（MUST NOT）、その存在をエラーとして扱ってはならず（MUST NOT）、依然としてカタログ配列を消費しなければなりません（MUST）。セールス認可もカタログコンテンツもないファイルは無効です。下記のエントリごとのフィールドは配列が空でない場合にのみ適用されます。

* **`url`** *(必須)*: エージェントの API エンドポイント URL
* **`authorized_for`** *(必須)*: 人間可読な認可の説明
* **`authorization_type`** *(必須)*: どのセレクターフィールドがスコープを運ぶかを名付ける識別子。`property_ids`、`property_tags`、`inline_properties`、`publisher_properties`（プロパティ用）または `signal_ids`、`signal_tags`（シグナルプロバイダー用）のいずれか。対応するセレクターフィールドが存在し空でない必要があります — 下記 [認可パターン](#認可パターン) を参照。
* **`delegation_type`** *(任意)*: このパスの商業的関係: `direct`、`delegated`、または `ad_network`
* **`collections`** *(任意)*: 認可を特定のコンテンツプログラムに狭める追加のコレクションセレクター
* **`placement_ids`** *(任意)*: 認可を特定のプレースメントに狭めるトップレベル `placements` 配列からのプレースメント ID
* **`placement_tags`** *(任意)*: 認可を管理されたプレースメントグループに狭めるパブリッシャー定義のプレースメントタグ
* **`countries`** *(任意)*: 認可が適用される場所を制限する ISO 3166-1 alpha-2 国コード
* **`effective_from` / `effective_until`** *(任意)*: 認可の時間ウィンドウ
* **`exclusive`** *(任意)*: これがスコープされたインベントリスライスに対するパブリッシャーの唯一の認可されたパスかどうか
* **`signing_keys`** *(任意)*: 署名付きエージェントレスポンスを検証する際にバイヤーがピン留めできる、パブリッシャーが証明した公開鍵
* **`last_updated`** *(任意)*: この `authorized_agents[]` エントリが最後に変わった ISO 8601 タイムスタンプ。ファイルレベルの `last_updated` とは独立。アドバイザリ — バリデーターが部分的なウォークで変更されていないエントリをスキップできるようにします。それが可能にする条件付きリフレッシュプロトコルについては [managed-networks security](/docs/governance/property/managed-networks#security-considerations) を参照。
* **追加フィールド**: authorization\_type に依存（後述のパターン参照）

**`revoked_publisher_domains`** *(任意、管理ネットワーク用)*: 管理ネットワークの権威あるファイルから明示的に削除されたパブリッシャードメインのトップレベル配列。各エントリは `publisher_domain`、`revoked_at`（ISO 8601）、任意の `reason` を持ちます。バリデーターは、ファイルの他の場所に現れるかどうかに関係なく、リストされたドメインをもはや認可されていないものとして扱わなければなりません（MUST）。運用ライフサイクルとバリデーター側の耐久性ルールについては [Publisher revocation](/docs/governance/property/managed-networks#publisher-revocation-the-exit-lifecycle) を参照。

**`last_updated`** *(任意)*: 最終更新の ISO 8601 タイムスタンプ

**`property_features`** *(任意)*: このファイル内のプロパティに関するデータを提供するガバナンスエージェントの配列

* **`url`** *(必須)*: エージェントの API エンドポイント URL（プロパティガバナンスタスクを実装するガバナンスエージェント）
* **`name`** *(必須)*: ベンダー/エージェントの人間可読な名前
* **`features`** *(必須)*: このエージェントが提供する Feature ID の配列（例: `["carbon_score", "mfa_score"]`）
* **`publisher_id`** *(任意)*: そのエージェント側でのパブリッシャー識別子（ルックアップ用）

このフィールドにより **ガバナンスエージェントの発見** が可能になり、バイヤーは全エージェントを総当たりせずに、どのエージェントがコンプライアンス/サステナビリティ/品質データを持つかを把握できます。

## Community mirror lifecycle

プラットフォームが AdCP を採用していない場合（例: 独自の `adagents.json` を公開していないウォールドガーデン）、AdCP コミュニティレジストリはプラットフォームに代わって**カタログのみのコミュニティミラー**を公開できます — 通常は `https://creative.adcontextprotocol.org/translated/<platform>/adagents.json` でホストされます。ミラーは、プラットフォームが自己採用する前にバイヤーがプラットフォームのインベントリ形状について推論できるよう、ディスカバリーメタデータ（`formats`、`properties`、`placements`）を公開するために存在します。

コミュニティミラーは:

* **`authorized_agents: []`** を設定します — 認可するセールスエージェントがなく、ミラーは 1 つを捏造してはなりません（MUST NOT）。空の配列は*セールス認可なし*を主張します。バリデーターはそれを deny-all、authorize-all、または失効として読んではならず（MUST NOT）、依然としてカタログ配列を消費しなければなりません（MUST）。
* 少なくとも 1 つの空でないカタログ配列（`formats`/`properties`/`placements`/`collections`/`signals`）を運ばなければならず（MUST）、**`catalog_etag`** キャッシュバリデーターを運ぶべきです（SHOULD。バリデーターは `catalog_etag` ではなく配列を強制します）。セールス認可もカタログコンテンツもないファイルは無効です。
* プラットフォームが独自の権威ある `adagents.json` を公開したら **`superseded_by`** を設定します。`superseded_by` に遭遇したバイヤー SDK は、古いミラーを提供するのではなく、名付けられた URL から再取得すべきです（SHOULD）。ミラーは、ミラー URL をキーとするバイヤーキャッシュが明示的な移行シグナルを得られるよう、少なくとも 1 つのマイナーリリースの間、`superseded_by` を設定したまま提供を続けるべきです（SHOULD）。

[`static/examples/adagents/community/meta.json`](https://github.com/adcontextprotocol/adcp/blob/main/static/examples/adagents/community/meta.json) のワークド例を参照。

## URL 参照パターン

複雑なインフラや CDN 配信を行うパブリッシャーは、全文を埋め込む代わりに信頼できる URL への参照を記載できます。

### URL 参照を使う場合

* **CDN 配信**: 認可データをグローバル CDN から配信
* **集中管理**: 複数ドメインを単一のソースで管理
* **大規模ファイル**: インライン埋め込みには大きすぎる場合
* **動的更新**: ドメイン上のファイルを触らず頻繁に更新したい場合

### URL 参照の構造

```json theme={null}
{
  "$schema": "https://adcontextprotocol.org/schemas/v3/adagents.json",
  "authoritative_location": "https://cdn.example.com/adagents/v2/adagents.json",
  "last_updated": "2025-01-15T10:00:00Z"
}
```

### 要件

* **HTTPS 必須**: `authoritative_location` は HTTPS を使用
* **入れ子禁止**: 参照先がさらに URL 参照であってはなりません（無限ループ防止）
* **同一スキーマ**: 参照先は有効なインライン adagents.json 構造であること
* **1 ホップのみ**: URL 間接参照は 1 段階まで

## Discovery fallback: ads.txt `managerdomain`

<Warning>
  これは既存の ads.txt 時代のパブリッシャー・マネージャー設定のための**レガシー互換フォールバック**です。
  AdCP の管理ネットワークデプロイでは、規範的な委任パターンは依然としてパブリッシャー自身の
  `/.well-known/adagents.json` ポインターファイルの [`authoritative_location`](/docs/governance/property/managed-networks) です。
  新しいデプロイはそのパターンを使うべきです（SHOULD）。
</Warning>

`https://{publisher}/.well-known/adagents.json` が `404` を返す、または S3/CloudFront スタイルの `403` `AccessDenied` XML レスポンスを返す場合、バリデーターは `https://{publisher}/ads.txt` を通じて互換フォールバックを試みてもかまいません（MAY）。

1. `ads.txt` を読み、`managerdomain` エントリをパースします。
   * 受け入れられる形式: `MANAGERDOMAIN=example.com`（IAB ディレクティブ形式のみ）。
   * キーマッチングは大文字小文字を区別しません（`MANAGERDOMAIN`、`managerdomain` など）。
   * このフォールバックをサポートするバリデーターは、`ads.txt` を取得する際に、各リダイレクトホップに同じ SSRF とパブリックホストのチェックを適用しながら、上限付きの HTTP リダイレクトチェーンに従うべきです（SHOULD）。
2. 1 つ以上の適格な managerdomain エントリが残る場合、ファイル順で**最後**の適格エントリを使い、`https://{managerdomain}/.well-known/adagents.json` を試みます。
3. そのマネージャーファイルが検証され、**認可をソースパブリッシャードメインに明示的にスコープする**場合、このルックアップで発見された認可ソースとして扱います。

### Safety rules for this fallback

* **1 ホップのみ**: 最大深さは正確に 1（`publisher -> managerdomain`）です。managerdomain ルックアップをチェーンしないでください。
* **サイクル検出が必須**: `managerdomain` が訪問済みドメインを指す場合、無視します。
* **`#noagents` オプトアウト**: managerdomain 行に `noagents` トークン（大文字小文字を区別しない）を含む末尾コメントがある場合、クライアントは adagents ディスカバリーについてその managerdomain を無視しなければなりません（MUST）。例: `MANAGERDOMAIN=example.com #NOAGENTS`。
* **トリガーステータスは狭い**: バリデーターは、パブリッシャーの直接の `adagents.json` フェッチが `404` または S3/CloudFront スタイルの `403` `AccessDenied` XML レスポンスを返す場合にのみ、このフォールバックを試みるべきです（SHOULD）。その他のステータスと失敗 — 汎用的な `403` 拒否、`500`、タイムアウト、不正な JSON、content-type 不一致、スキーマ検証失敗 — は `managerdomain` をトリガーしません。
* **明示的なパブリッシャースコープが必須**: マネージャーがホストする `adagents.json` は、少なくとも 1 つの `authorized_agents[]` エントリから到達可能な `publisher_domain` フィールドで、ソースパブリッシャードメインを積極的に名付けなければなりません（MUST）。「到達可能」とは、次のパスの 1 つがソースドメインに解決することを意味します。

  1. **エージェントごとのパス。** エージェントエントリが、`publisher_properties[].publisher_domain` の下、`publisher_properties[].publisher_domains[]` の内部（コンパクトな管理ネットワーク形式）、または `collections[].publisher_domain` の下で、パブリッシャードメインを直接運ぶ。
  2. **プロパティレベルのパス。** エージェントエントリが 1 つ以上のトップレベル `properties[]` エントリを参照する — エージェントエントリ上の ID/タグで直接（`property_ids` / `property_tags` の authorization\_type）、または一致する `publisher_domain` を運ぶ親ファイルの `properties[]` によって述語が満たされる `publisher_properties` セレクターを通じて間接的に（下記 [Resolution paths](#resolution-paths) を参照）— そして少なくとも 1 つの解決されたプロパティがソースに一致する `publisher_domain` を運ぶ。これは、プロパティが `publisher_domain` を一度宣言し多くのエージェントが間接的に参照する、Mediavine や他の管理ネットワークが本番で使う形状です。

  このルールを**満たさない**もの: `publisher_domain` を省略するインラインプロパティを持つ `inline_properties` セレクター、または解決されたトップレベルプロパティが一致する `publisher_domain` を運ばないトップレベル `property_tags` セレクター。到達可能な `publisher_domain` フィールドがソースに一致しない場合、フォールバックはフェイルクローズしなければなりません（MUST）。

  これが保護する攻撃は暗黙的スコープ — マネージャーがドメインをタイプしなければならない場所のどこにもパブリッシャーを名付けない認可 — です。`properties[].publisher_domain` を通じた間接参照は安全です。マネージャーが同じマニフェストでパブリッシャーのドメインを積極的に綴っているからです。ゲートは、参照を考慮する前に `publisher_domain` がソースに一致するプロパティにフィルタリングします。
* **沈黙による成功なし**: マネージャールックアップが失敗した場合、パブリッシャーを `adagents.json` が欠けているものとして扱います（フォールバックなしと同じ）。

このフォールバックは、パブリッシャー・マネージャートポロジーのための互換アフォーダンスであり、正準の `/.well-known/adagents.json` の場所を置き換えるものではありません。

### ユースケース: 複数ドメインを持つパブリッシャー

複数ドメインを持つパブリッシャーは 1 つの権威ファイルを維持できる:

**各ドメイン上** (`https://domain1.com/.well-known/adagents.json`, `https://domain2.com/.well-known/adagents.json` など):

```json theme={null}
{
  "$schema": "https://adcontextprotocol.org/schemas/v3/adagents.json",
  "authoritative_location": "https://cdn.publisher.com/adagents/v2/adagents.json",
  "last_updated": "2025-01-15T10:00:00Z"
}
```

**権威ファイル** (`https://cdn.publisher.com/adagents/v2/adagents.json`):

```json theme={null}
{
  "$schema": "https://adcontextprotocol.org/schemas/v3/adagents.json",
  "contact": {
    "name": "Publisher Ad Operations",
    "email": "adops@publisher.com"
  },
  "properties": [
    {
      "property_id": "domain1_site",
      "property_type": "website",
      "name": "Domain 1",
      "identifiers": [{"type": "domain", "value": "domain1.com"}],
      "publisher_domain": "domain1.com"
    },
    {
      "property_id": "domain2_site",
      "property_type": "website",
      "name": "Domain 2",
      "identifiers": [{"type": "domain", "value": "domain2.com"}],
      "publisher_domain": "domain2.com"
    }
  ],
  "authorized_agents": [
    {
      "url": "https://sales-agent.publisher.com",
      "authorized_for": "All publisher properties",
      "authorization_type": "property_ids",
      "property_ids": ["domain1_site", "domain2_site"]
    }
  ],
  "last_updated": "2025-01-15T09:00:00Z"
}
```

### 検証時の挙動

AdCP の検証で URL 参照が見つかった場合:

1. **参照取得**: `/.well-known/adagents.json` を取得
2. **参照検出**: `authoritative_location` を確認
3. **URL 検証**: `authoritative_location` が HTTPS かつ有効か確認
4. **参照先取得**: `authoritative_location` の内容を取得
5. **ループ防止**: 参照先がさらに参照でないことを確認
6. **構造検証**: 参照先を通常のインライン構造として検証

### Troubleshooting authoritative\_location failures

URL 参照を通じてエージェントを登録するパブリッシャーは、これらの失敗モードによく遭遇します。サポートに問い合わせる前にこのチェックリストを使ってください。

**オリジンが認証または IP 制限を要求する**

バリデーターは `authoritative_location` をサーバー側で取得します — サーバー間リクエストに CORS レスポンスヘッダーは不要です。しかし、オリジンが認証を要求する場合（例: 制限的なバケットポリシーを持つ S3 バケット、未知の IP をブロックするオリジン保護を持つ CDN）、フェッチは `403` で拒否されます。URL が認証なしで公開的に到達可能であることを確認してください。

**authoritative URL でのリダイレクト**

バリデーターは `authoritative_location` URL 上の任意の HTTP リダイレクトを拒否します。URL は `200` レスポンスで JSON ファイルに直接解決しなければなりません — `301`、`302`、その他のリダイレクトチェーンなし。CDN やホスティングが URL をリダイレクトする場合（HTTP→HTTPS 正規化、`www` リダイレクト、バージョン付きパスリダイレクト）、`authoritative_location` を最終的な宛先 URL を直接指すように更新してください。

**誤った Content-Type**

レスポンスは `Content-Type: application/json` で提供されなければなりません。`text/html` や `text/plain` を返すサーバーは — ボディが有効な JSON を含む場合でも — content-type 検証に失敗します。CDN やオリジンのレスポンスヘッダーを確認してください。

**200 ステータスの HTML エラーページ**

一部の CDN は、`4xx` ステータスの代わりに `200 OK` で HTML エラーページを返します。バリデーターは `Content-Type` ヘッダーをチェックし JSON パースを試みます。HTML ボディはステータスが `200` でもパースに失敗します。バリデーター出力で `200` ステータスとともにパースエラーを探してください。

**デバッグチェックリスト**

これらの失敗を診断するために、バリデーターのフェッチをターミナルから再現します。

```bash theme={null}
curl -v \
  -H "Accept: application/json" \
  "https://cdn.example.com/adagents.json"
```

出力で次を確認します。

* レスポンスステータスが `200`（`301`、`302`、`403`、`404` ではない）
* `Content-Type` ヘッダーが `application/json`
* レスポンスボディが `properties`、`signals`、`authorized_agents` の少なくとも 1 つを含む有効な JSON
* ボディが `authoritative_location` フィールドを含**まない**（入れ子参照は拒否される）

クローラーが診断エンドポイントを公開している場合、構造化されたエラー出力のために URL をそこに通してください。

### キャッシュ推奨

* 参照ファイルは最低 24 時間キャッシュ
* 権威ファイルは別途 TTL を設定してキャッシュ
* `last_updated` でキャッシュ無効化を判断
* 取得失敗時は指数バックオフを実装

## 認可パターン

AdCP は 4 種の認可パターンをサポートし、用途に最適化されています:

### パターン 1: Property IDs（直接参照）

**最適な用途**: 具体的で列挙可能なプロパティリスト。明確で曖昧さがない。

**構造**:

```json theme={null}
{
  "properties": [
    {
      "property_id": "cnn_ctv_app",
      "property_type": "ctv_app",
      "name": "CNN CTV App",
      "identifiers": [
        {"type": "roku_store_id", "value": "12345"}
      ]
    }
  ],
  "authorized_agents": [
    {
      "url": "https://cnn-ctv-agent.com",
      "authorized_for": "CNN CTV properties",
      "authorization_type": "property_ids",
      "property_ids": ["cnn_ctv_app"]
    }
  ]
}
```

**仕組み**: エージェントは `property_ids` 配列に列挙された特定プロパティのみを認可されます。プロパティはトップレベルの `properties` 配列で定義されていなければなりません。

### パターン 2: Property Tags（効率的なグルーピング）

**最適な用途**: 1 つのタグで数百〜数千のプロパティを参照できる大規模ネットワーク。全 property\_id を列挙せずにグルーピング効率を実現します。

**重要な観点**: タグは単なる「人が読めるメタデータ」ではなく、**パフォーマンス最適化**です。500 プロパティを持つパブリッシャーは 1 つのタグで全プロパティを認可でき、500 個の property\_id を列挙する必要がない。

**構造**:

```json theme={null}
{
  "properties": [
    {
      "property_id": "instagram",
      "property_type": "mobile_app",
      "name": "Instagram",
      "identifiers": [
        {"type": "ios_bundle", "value": "com.burbn.instagram"}
      ],
      "tags": ["meta_network", "social_media"]
    },
    {
      "property_id": "facebook",
      "property_type": "mobile_app",
      "name": "Facebook",
      "identifiers": [
        {"type": "ios_bundle", "value": "com.facebook.Facebook"}
      ],
      "tags": ["meta_network", "social_media"]
    }
  ],
  "tags": {
    "meta_network": {
      "name": "Meta Network",
      "description": "All Meta-owned properties - enables one tag to authorize entire network"
    }
  },
  "authorized_agents": [
    {
      "url": "https://meta-ads.com",
      "authorized_for": "All Meta properties",
      "authorization_type": "property_tags",
      "property_tags": ["meta_network"]
    }
  ]
}
```

**仕組み**: エージェントはリストされたタグのいずれかを持つすべてのプロパティを認可されます。プロパティは各プロパティ定義の `tags` 配列と照合されます。

### パターン 3: Inline Properties

**最適な用途**: トップレベルのプロパティ宣言なしに小規模・特定のプロパティ集合を扱う場合。

**構造**:

```json theme={null}
{
  "authorized_agents": [
    {
      "url": "https://agent.com",
      "authorized_for": "Specific inventory",
      "authorization_type": "inline_properties",
      "properties": [
        {
          "property_type": "website",
          "name": "Example Site",
          "identifiers": [
            {"type": "domain", "value": "example.com"}
          ]
        }
      ]
    }
  ]
}
```

**仕組み**: プロパティはトップレベルの `properties` 配列ではなく、エージェント認可エントリ内で直接定義されます。各エージェントが固有のプロパティ定義を持つ場合に便利。

### パターン 4: Publisher Property References

**最適な用途**: 複数のパブリッシャーを代表するサードパーティエージェント。プロパティ定義の単一のソース・オブ・トゥルース。

**構造**:

```json theme={null}
{
  "contact": {
    "name": "Third-Party CTV Network"
  },
  "authorized_agents": [
    {
      "url": "https://ctv-network.com/api",
      "authorized_for": "CTV inventory from multiple publishers",
      "authorization_type": "publisher_properties",
      "publisher_properties": [
        {
          "publisher_domain": "cnn.com",
          "selection_type": "by_tag",
          "property_tags": ["ctv"]
        },
        {
          "publisher_domain": "espn.com",
          "selection_type": "by_tag",
          "property_tags": ["ctv"]
        }
      ]
    }
  ]
}
```

**仕組み**: エージェントは他のパブリッシャーの adagents.json ファイルからプロパティを参照します。`publisher_domain` でパブリッシャーを指定し、`selection_type` でプロパティの解決方法（`by_id` または `by_tag`）を決定します。

### Resolution paths

`publisher_properties` セレクターは、2 つの方法のいずれかでプロパティに解決します。フェデレーテッドがデフォルトで信頼のルートです。親ファイルインラインは、親ファイルがセレクターをローカルに解決するのに十分な情報を運ぶときにコンシューマーが取ってもよい（MAY）ドメインごとの最適化です。

**1. フェデレーテッド解決（デフォルト）。** `publisher_domain` または `publisher_domains[]` の各ドメインについて、そのパブリッシャーの `adagents.json` を取得し、セレクター述語をパブリッシャー自身のトップレベル `properties[]` に適用します。リストされた各ドメインは**独立して並行に**解決されます。

* リストされたパブリッシャーの `adagents.json` が到達不能（404、5xx、タイムアウト、自身の検証に失敗）な場合、セレクターは**そのパブリッシャーについてのみ**空集合に解決します — エントリは他のすべてのリストされたパブリッシャーについて有効なままです。コンシューマーは、単一の到達不能なパブリッシャーがコンパクトエントリの残りを汚染するものとして扱ってはなりません（MUST NOT）。
* リストされたパブリッシャーの `adagents.json` が述語に一致するプロパティを運ばない（名付けられたタグを持つエントリがない）場合、セレクターはそのパブリッシャーについて空集合に解決します。同じ部分解決ルールが適用されます。
* 解決キャッシュは、各パブリッシャー自身の `adagents.json` のキャッシュポリシーに独立して従います。コンシューマーは、同じコンパクトエントリ内の別のパブリッシャーの観察に基づいて、あるパブリッシャーのキャッシュ TTL を延長または短縮すべきではありません（SHOULD NOT）。

**2. 親ファイルインライン解決（管理ネットワーク最適化）。** コンシューマーは、**すべて**の次が成り立つとき、親ファイル自身のトップレベル `properties[]` からセレクターを満たしてもかまいません（MAY）。

* 親ファイルがトップレベル `properties[]` エントリを持つ。
* 一致するすべてのプロパティが、値がセレクターの `publisher_domain` / `publisher_domains[]` セットのドメインの 1 つに等しい明示的な `publisher_domain` フィールドを運ぶ。
* `selection_type: by_tag` の場合: プロパティの `tags[]` がセレクターの `property_tags[]` の少なくとも 1 つを含む。
* `selection_type: by_id` の場合: プロパティの `property_id` がセレクターの `property_ids[]` にあり、かつセレクターが単数形の `publisher_domain` 形式を使う（コンパクトな `publisher_domains[]` 形式は `by_id` では依然として拒否されます — プロパティ ID はパブリッシャースコープであり、固定 ID セットを複数パブリッシャーにファンアウトすると誤ったインベントリを黙って認可することになるため）。
* `selection_type: all` の場合: 一致する `publisher_domain` を持つすべての親ファイル `properties[]` エントリが選択される。

インライン解決は**ドメインごとの最適化**です: コンシューマーは、親ファイルに一致するインラインプロパティを持つリストされたドメインにはインライン解決を、残りにはフェデレーテッド解決を使ってもかまいません（MAY）。両方が利用可能な場合、両パスは同じ `(publisher_domain, property_id)` セットを生成すべきです（SHOULD）。

**なぜこれが安全か。** プロパティ認可の信頼アンカーは、プロパティ上でドメインが名付けられたパブリッシャーです。各インラインプロパティに `publisher_domain` を要求しセレクターの `publisher_domains[]` と照合することで、インラインパスは、インベントリが認可されているパブリッシャーが明示的に名付けられているという不変条件 — [`managerdomain` フォールバックの安全ルール](#safety-rules-for-this-fallback)が保護するのと同じ不変条件 — を保持します。マネージャーファイルは、リストしていないパブリッシャーのインベントリを認可するためにインライン解決を使えません。

**乖離ルール。** コンシューマーが同じ `(publisher_domain, property_id)` をインラインとフェデレーテッドの両パスで解決し結果が食い違う場合、フェデレーテッドの結果が権威を持ちます。コンシューマーは乖離をパブリッシャー側のデータ整合性警告としてログに記録すべきで（SHOULD）、オペレーターに表面化してもかまいません（MAY）。厳格なフェデレーションを好むコンシューマーはインラインパスを完全に無視してもかまいません（MAY）。

**インライン解決下での失効。** インライン解決は親ファイルの `revoked_publisher_domains[]` を尊重しなければなりません（MUST）。親レベルで失効としてリストされた `publisher_domain` は、親の `properties[]` に一致するプロパティが存在するかどうかに関係なく、そのドメインについて空集合に解決します。フェデレーテッドも解決するコンシューマーは、子自身の `revoked_publisher_domains[]` をクロスチェックすべきです（SHOULD）。最初の一致（親または子）が失効させます。

**どちらをいつ使うか。** インライン解決が存在するのは、管理ネットワーク規模（1 オペレーターの下で数千の代表パブリッシャー）での厳格なフェデレーションが認可チェックごとに N 回の HTTP フェッチを必要とし、どの本番コンシューマーも維持できないためです。`publisher_domain` アンカーとともに `properties[]` をインライン化するファイルは「ここで解決できる」とシグナルしています。小さなフェデレーテッドエントリ（少数のパブリッシャー、それぞれ適切に投入された独自の `adagents.json` を持つ）を扱うコンシューマーはフェデレーテッドパスを好むべきです。それはコンシューマー側の信頼の前提が少ないです。管理ネットワークの親ファイルを大規模にインデックスするコンシューマーはインラインパスを好むべきです。親ファイルは仕様が是認するかどうかに関係なく構造的にプロパティカタログであり、インライン解決がそれを明示的にします。

## Authorization Qualifiers

上記の 4 つのプロパティ側 `authorization_type` パターンは、エージェントが**どのインベントリ**を販売できるかに答えます。2 つのシグナル側の値（`signal_ids`、`signal_tags`）は `signals[]` について同じ形状を運びます。下記の任意の修飾子は、そのインベントリが**どのように**利用可能にされているかに答えます。

### `delegation_type`

* **`direct`**: パブリッシャーは、第三者が舞台裏でソフトウェアを運用していても、このエンドポイントを自分たちから購入する直接的な方法として扱います
* **`delegated`**: エージェントはパブリッシャーを代行して販売することを認可されています
* **`ad_network`**: インベントリはパブリッシャーの直接エンドポイントとしてではなく、ネットワーク/パッケージ販売パスを通じて販売されます

### `collections`

認可が特定のコンテンツプログラムに関連付けられたインベントリにのみ適用されるべき場合に `collections` を使います。これは、同じプロパティが異なる商業的取り決めを持つ多くのコレクションを運びうる CTV、ストリーミング、ポッドキャスティング、クリエイターインベントリに特に有用です。

### `placement_ids`

認可を同じ `adagents.json` に公開された正準プレースメントに狭めるために `placement_ids` を使います。これは、パブリッシャーが「このエージェントは MSN ホームページネイティブフィードに認可されているが、プロパティ全体ではない」や「このネットワークはプレロールを販売できるがホストリードスポンサーシップは販売できない」と言えるようにするフィールドです。プロダクトレスポンスとクリエイティブ割り当てでは、対応するプレースメントアイデンティティは `{ publisher_domain, placement_id }` です。

正準プレースメント定義は次も運べます。

* プロパティとプロダクト間でプレースメントをグループ化する `tags`
* 「プロパティ X にはどのプレースメントがあるか？」「プレースメント Y はどのプロパティにあるか？」に答える `property_ids` または `property_tags`
* プロダクトレスポンスのプレースメント詳細に完全に依存せずに「このプレースメントはどのフォーマットをサポートするか？」に答える `format_options`

### `placement_tags`

認可が手動保守されたプレースメント ID のリストではなく管理されたプレースメントグループに適用されるべき場合に `placement_tags` を使います。これは次のような商業アクセスパターンに有用です。

* `programmatic`
* `direct_only`
* `publisher_managed`
* `managed_by_taboola`

自由形式のラベルとは異なり、これらのタグは認可決定がそれらに依存するため、パブリッシャーのプレースメントガバナンスモデルの一部として扱われるべきです。プロパティタグがトップレベル `tags` で文書化されるのと同じ方法で、トップレベル `placement_tags` メタデータで定義します。

### `signing_keys`

パブリッシャーが、認可されたエージェントが署名に使える公開鍵をピン留めしたい場合に `signing_keys` を使います。これは、エージェントドメインのみからの鍵ディスカバリーを信頼することを避けます。

* これらは単なる便宜メタデータではなく、パブリッシャーが証明した信頼アンカーです
* バイヤーは、`adagents.json` のピン留めされた鍵に対して署名付きエージェントレスポンスを検証すべきです
* エージェントドメインが侵害された場合、ピン留めされた鍵は攻撃者がエンドポイントとそのアドバタイズされた鍵の両方を黙って入れ替えるのを防ぎます

パブリッシャーは、委任されたスコープに**変更操作** — パブリッシャーを代行して状態を書き込む任意の AdCP タスク — を含む任意の認可エージェントについて `signing_keys` を投入しなければなりません（MUST）。3.x カタログでは、これはメディアバイタスクセット（`create_media_buy`、`update_media_buy`、`sync_creatives`、`update_performance_index`）と、[media-buy タスクリファレンス](/docs/media-buy/task-reference/update_media_buy)で変更としてフラグ付けされる将来のタスクを意味します。読み取り専用のディスカバリータスク（`get_products`、`get_signals`、`list_creative_formats`）はこの要件の対象外です。変更スコープの認可について `signing_keys` を空のままにすると、信頼チェーンが取引相手が制御する `jwks_uri` ディスカバリーに縮小され、クロスチェックとしてのパブリッシャーのピンが失われます。

検証者要件: パブリッシャーのエージェント用 `adagents.json` エントリが `signing_keys` を含む場合、検証者は、`jwks_uri` の内容に関係なく、`keyid` がそのピン留めされたセットにない任意の署名を拒否しなければなりません（MUST）。ピンが権威を持ちます。エージェントがホストする JWKS はアドバイザリであり、それをオーバーライドしてはなりません（MUST NOT）。

**鍵ローテーションとキャッシュセマンティクス。** ローテーション・バイ・DoS ウィンドウを開かずにローテーション間でピンを使用可能に保つには:

* 検証者は、ピン留めされた `signing_keys` を、パブリッシャーが `adagents.json` で提供する `Cache-Control` `max-age` を最大としてキャッシュすべきで（SHOULD）、ディレクティブがない場合は**1 時間**をデフォルトとします。より長いキャッシュは、正当なローテーションされた鍵を拒否するリスクがあります。
* **未知の `keyid`** に遭遇したとき、検証者は最終的な拒否の前にパブリッシャーの `adagents.json` を強制リフレッシュ（キャッシュをバイパス）しなければなりません（MUST）。これは、古いキャッシュが正当にローテーションされた鍵をロックアウトするのを防ぎます。
* パブリッシャーは、検証者が古い鍵または新しい鍵の下で生成された署名を受け入れられるよう、ローテーションウィンドウ中に `signing_keys` に**重複する鍵**を運んでもかまいません（MAY）。ピン留めされたセットは順序なしです: セット内の存在が受け入れに十分です。オペレーターは、進行中のトラフィックがまだそれで署名していないと確信したら、退役した鍵をピンから削除すべきです（SHOULD。日単位ではなく時間単位）。

**ブートストラップスコープ。** ピンは**エージェントドメイン**の侵害から保護します: エージェントドメインが乗っ取られても、パブリッシャーのピンが依然として受け入れを管理するため、攻撃者はエンドポイントとそのアドバタイズされた鍵の両方を黙って入れ替えられません。パブリッシャードメインの侵害からは保護し**ません**（`adagents.json` を制御する攻撃者はピン自体を書き換えられます）。`adagents.json` の初回取得は TLS 信頼のみです。R-1 の信頼のルート / 鍵透明性の作業（`specs/registry-change-feed.md` §Feed-event content signing で追跡）が、この境界を強化するトラックです。

変更スコープの認可について `signing_keys` を任意からスキーマレベルで必須に昇格させるフォローアップが追跡されています。そのスキーマ変更が到着するまで、上記の文章要件が規範的な下限です。

### `countries`

認可を地理的に制約するために ISO 3166-1 alpha-2 国コードを使います。これは「LATAM」や「EMEA」などの曖昧な地域略称を避け、バイヤーエージェントに正確な機械可読なスコープを与えます。

### `effective_from` / `effective_until`

季節的独占、ウィンドウ化されたシンジケーション、一時的な委任販売合意などの時間限定の権利にこれらのフィールドを使います。

### `exclusive`

このエージェントがスコープされたインベントリスライスに対するパブリッシャーの唯一の認可されたパスである場合に `exclusive: true` を設定します。複数のエージェントが同時に認可されている場合は、省略するか `false` に設定します。

### Example: Scoped Delegation

```json theme={null}
{
  "placement_tags": {
    "programmatic": {
      "name": "Programmatic",
      "description": "Placements available through programmatic sales paths"
    },
    "direct_only": {
      "name": "Direct only",
      "description": "Placements reserved for direct publisher sales"
    }
  },
  "collections": [
    {
      "collection_id": "signal_noise",
      "name": "Signal & Noise",
      "kind": "series"
    }
  ],
  "placements": [
    {
      "placement_id": "pre_roll",
      "name": "Pre-roll",
      "tags": ["audio", "pre_roll", "programmatic"],
      "property_ids": ["publisher_podcast"],
      "collection_ids": ["signal_noise"],
      "format_options": [
        {
          "format_kind": "audio_hosted",
          "params": {
            "duration_ms_exact": 15000,
            "audio_codecs": ["mp3"]
          }
        }
      ]
    },
    {
      "placement_id": "host_read",
      "name": "Host-read Mid-roll",
      "tags": ["audio", "host_read", "premium", "direct_only"],
      "property_ids": ["publisher_podcast"],
      "collection_ids": ["signal_noise"],
      "format_options": [
        {
          "format_kind": "audio_hosted",
          "params": {
            "duration_ms_exact": 60000,
            "asset_source": "publisher_host_recorded",
            "buyer_asset_acceptance": "rejected"
          }
        }
      ]
    }
  ],
  "authorized_agents": [
    {
      "url": "https://sales.publisher.example.com",
      "authorized_for": "Direct US and CA sales for Signal & Noise host reads",
      "authorization_type": "property_ids",
      "property_ids": ["publisher_podcast"],
      "collections": [
        {
          "publisher_domain": "publisher.example.com",
          "collection_ids": ["signal_noise"]
        }
      ],
      "placement_tags": ["direct_only"],
      "delegation_type": "direct",
      "countries": ["US", "CA"],
      "exclusive": true
    },
    {
      "url": "https://network.example.com",
      "authorized_for": "Open network distribution outside US and CA for pre-roll",
      "authorization_type": "property_ids",
      "property_ids": ["publisher_podcast"],
      "collections": [
        {
          "publisher_domain": "publisher.example.com",
          "collection_ids": ["signal_noise"]
        }
      ],
      "placement_tags": ["programmatic"],
      "delegation_type": "ad_network",
      "countries": ["GB", "AU", "NZ"]
    }
  ]
}
```

これにより、パブリッシャーは、すべての認可パスが同等であることを意味することなく、「一部の市場では私たちから直接ホストリードを購入し、他の市場ではプレロールにネットワークパスを使う」と言えます。

`adagents.json` は現在、正準のパブリッシャーレベルのプレースメントレジストリを提供します。プロダクトは依然として独自の `placements` を返しますが、プレースメント ID はパブリッシャースコープです: カタログバックのプレースメントは `{ publisher_domain, placement_id }` でパブリッシャーレジストリを参照すべきです（SHOULD）。プロダクトが複数のパブリッシャーにまたがりカタログ ID が衝突する場合、`publisher_domain` がそれらを曖昧性解消します。それらのケースについてクリエイティブ割り当ては構造化された `placement_refs` を使うべきです。カタログプレースメントを参照することは、プロダクトがそのプレースメントのアイデンティティを継承することを意味します。プロダクトは `format_ids` を狭めたり、プレースメントタグを保持または狭めたり、運用の詳細を追加したりできますが、プレースメントを互換性のないものに再定義すべきではありません。

## ドメインマッチングルール

ドメイン識別子を持つウェブサイトプロパティについて、AdCP はウェブの慣例に従います。

### ベースドメイン（`example.com`）

ドメイン本体と標準的なウェブサブドメインにマッチします。

* ✅ `example.com`
* ✅ `www.example.com`（標準ウェブ）
* ✅ `m.example.com`（標準モバイル）
* ❌ `subdomain.example.com`（明示的な認可が必要）

### 特定サブドメイン（`subdomain.example.com`）

その特定サブドメインのみにマッチします。

* ✅ `subdomain.example.com`
* ❌ その他のすべてのドメイン/サブドメイン

### ワイルドカード（`*.example.com`）

すべてのサブドメインにマッチしますが、ベースドメインはマッチしません。

* ✅ 任意のサブドメイン
* ❌ `example.com`（ベースドメインは別途認可が必要）

## Real-World Examples

### Example 1: Meta Network (Tag-Based)

Large network using tags for grouping efficiency:

```json theme={null}
{
  "contact": {
    "name": "Meta Advertising Operations",
    "email": "adops@meta.com",
    "domain": "meta.com",
    "seller_id": "pub-meta-12345",
    "tag_id": "12345",
    "privacy_policy_url": "https://www.meta.com/privacy/policy"
  },
  "properties": [
    {
      "property_type": "mobile_app",
      "name": "Instagram",
      "identifiers": [
        {"type": "ios_bundle", "value": "com.burbn.instagram"},
        {"type": "android_package", "value": "com.instagram.android"}
      ],
      "tags": ["meta_network"],
      "publisher_domain": "instagram.com"
    },
    {
      "property_type": "mobile_app",
      "name": "Facebook",
      "identifiers": [
        {"type": "ios_bundle", "value": "com.facebook.Facebook"},
        {"type": "android_package", "value": "com.facebook.katana"}
      ],
      "tags": ["meta_network"],
      "publisher_domain": "facebook.com"
    },
    {
      "property_type": "mobile_app",
      "name": "WhatsApp",
      "identifiers": [
        {"type": "ios_bundle", "value": "net.whatsapp.WhatsApp"},
        {"type": "android_package", "value": "com.whatsapp"}
      ],
      "tags": ["meta_network"],
      "publisher_domain": "whatsapp.com"
    }
  ],
  "tags": {
    "meta_network": {
      "name": "Meta Network",
      "description": "All Meta-owned properties - one tag authorizes entire network efficiently"
    }
  },
  "authorized_agents": [
    {
      "url": "https://meta-ads.com",
      "authorized_for": "All Meta properties",
      "authorization_type": "property_tags",
      "property_tags": ["meta_network"]
    }
  ]
}
```

**Why this works**: One tag (`meta_network`) authorizes all properties without listing individual property IDs. As Meta adds properties, they just tag them - no need to update agent authorization.

### Example 2: CNN (Channel Segmentation)

Different agents for different channels:

```json theme={null}
{
  "contact": {
    "name": "CNN Advertising Operations",
    "email": "adops@cnn.com",
    "domain": "cnn.com"
  },
  "properties": [
    {
      "property_id": "cnn_ctv_app",
      "property_type": "ctv_app",
      "name": "CNN CTV App",
      "identifiers": [
        {"type": "roku_store_id", "value": "12345"}
      ],
      "tags": ["ctv"]
    },
    {
      "property_id": "cnn_web_us",
      "property_type": "website",
      "name": "CNN.com US",
      "identifiers": [
        {"type": "domain", "value": "cnn.com"}
      ],
      "tags": ["web"]
    }
  ],
  "authorized_agents": [
    {
      "url": "https://cnn-ctv-agent.com",
      "authorized_for": "CNN CTV properties",
      "authorization_type": "property_ids",
      "property_ids": ["cnn_ctv_app"]
    },
    {
      "url": "https://cnn-web-agent.com",
      "authorized_for": "CNN web properties",
      "authorization_type": "property_ids",
      "property_ids": ["cnn_web_us"]
    }
  ]
}
```

### Example 3: Publisher with Governance Agent References

Publishers can declare which governance agents have data about their properties using `property_features`. This enables buyers to discover where to get sustainability, quality, and suitability data.

```json theme={null}
{
  "$schema": "https://adcontextprotocol.org/schemas/v3/adagents.json",
  "contact": {
    "name": "Premium News Publisher",
    "email": "adops@news.example.com",
    "domain": "news.example.com"
  },
  "properties": [
    {
      "property_id": "news_main",
      "property_type": "website",
      "name": "News Example",
      "identifiers": [
        {"type": "domain", "value": "news.example.com"}
      ],
      "tags": ["premium", "news"],
      "publisher_domain": "news.example.com"
    }
  ],
  "tags": {
    "premium": {
      "name": "Premium Properties",
      "description": "High-quality, brand-suitable properties"
    },
    "news": {
      "name": "News Properties",
      "description": "News and journalism content"
    }
  },
  "authorized_agents": [
    {
      "url": "https://sales.news.example.com",
      "authorized_for": "All news properties",
      "authorization_type": "property_tags",
      "property_tags": ["news"]
    }
  ],
  "property_features": [
    {
      "url": "https://api.sustainability-vendor.example",
      "name": "Sustainability Vendor",
      "features": ["carbon_score", "green_media_certified"],
      "publisher_id": "pub_news_12345"
    },
    {
      "url": "https://api.quality-vendor.example",
      "name": "Quality Vendor",
      "features": ["mfa_score", "ad_density", "page_speed"]
    },
    {
      "url": "https://api.suitability-vendor.example",
      "name": "Suitability Vendor",
      "features": ["content_category", "brand_risk_score", "sentiment"],
      "publisher_id": "suit_news_67890"
    }
  ],
  "last_updated": "2025-01-10T18:00:00Z"
}
```

**Why this works**:

* Publishers declare relationships with governance agents upfront
* Buyers discover governance agents by reading adagents.json (no need to query every possible agent)
* The `publisher_id` field helps agents look up the publisher's data efficiently
* Feature IDs tell buyers what data types are available without querying

## Governance Agent Discovery

The `property_features` field solves a key discovery problem: how does a buyer know which governance agents have data about a given property?

```mermaid theme={null}
sequenceDiagram
    participant Buyer as Buyer Agent
    participant PubDomain as Publisher Domain
    participant SustAgent as Sustainability Agent
    participant QualAgent as Quality Agent

    Buyer->>PubDomain: GET /.well-known/adagents.json
    PubDomain-->>Buyer: adagents.json with property_features

    Note over Buyer: Extract governance agents from property_features

    par Query governance agents
        Buyer->>SustAgent: get_adcp_capabilities
        SustAgent-->>Buyer: Available features (carbon_score, etc.)
    and
        Buyer->>QualAgent: get_adcp_capabilities
        QualAgent-->>Buyer: Available features (mfa_score, etc.)
    end

    Note over Buyer: Create property lists on each governance agent

    Buyer->>SustAgent: create_property_list(filters, brand)
    Buyer->>QualAgent: create_property_list(filters, brand)
```

### When to Use property\_features

| Scenario                                                       | Use property\_features?        |
| -------------------------------------------------------------- | ------------------------------ |
| Publisher has carbon scoring from a sustainability vendor      | ✅ Yes                          |
| Publisher has MFA score measured by a quality vendor           | ✅ Yes                          |
| Publisher has content classification from a suitability vendor | ✅ Yes                          |
| Publisher self-reports brand suitability                       | ❌ No - use property tags       |
| Sales agent provides quality data                              | ❌ No - that's agent capability |

### Vendor Extensions

Governance agents can include vendor-specific data in feature definitions via an `ext` block. See [get\_adcp\_capabilities](/docs/protocol/get_adcp_capabilities) for details.

## Fetching and Validating

### Using the AdAgents.json Builder

The easiest way to validate or create an adagents.json file is using the **[AdAgents.json Builder](https://agenticadvertising.org/adagents/builder)** web tool. It provides:

* Domain validation (fetches and checks `/.well-known/adagents.json`)
* Structure validation against the JSON schema
* Agent card endpoint verification (checks if agent URLs respond correctly)
* Guided file creation with proper formatting

### Programmatic Validation

For programmatic validation, use the validation API:

<CodeGroup>
  ```javascript JavaScript theme={null}
  // Validate a domain's adagents.json file
  const response = await fetch('https://adcontextprotocol.org/api/adagents/validate', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ domain: 'example.com' })
  });

  const { success, data } = await response.json();

  if (success && data.found) {
    console.log(`Valid: ${data.validation.valid}`);
    console.log(`Agents: ${data.validation.raw_data?.authorized_agents?.length || 0}`);

    // Check for any validation errors
    if (data.validation.errors?.length > 0) {
      console.log('Errors:', data.validation.errors.map(e => e.message));
    }
  } else {
    console.log('No adagents.json found at this domain');
  }
  ```

  ```python Python theme={null}
  import httpx

  # Validate a domain's adagents.json file
  response = httpx.post(
      'https://adcontextprotocol.org/api/adagents/validate',
      json={'domain': 'example.com'}
  )

  result = response.json()

  if result['success'] and result['data']['found']:
      validation = result['data']['validation']
      print(f"Valid: {validation['valid']}")
      print(f"Agents: {len(validation.get('raw_data', {}).get('authorized_agents', []))}")

      # Check for any validation errors
      if validation.get('errors'):
          print('Errors:', [e['message'] for e in validation['errors']])
  else:
      print('No adagents.json found at this domain')
  ```

  ```bash CLI theme={null}
  # Validate a domain's adagents.json file
  curl -X POST https://adcontextprotocol.org/api/adagents/validate \
    -H "Content-Type: application/json" \
    -d '{"domain": "example.com"}' | jq '.data.validation'
  ```
</CodeGroup>

The validation API fetches `https://{domain}/.well-known/adagents.json`, validates its structure, follows URL references if present, and optionally checks agent card endpoints.

### Using AdCP Client Libraries

The AdCP client libraries provide built-in validation and authorization checking:

<CodeGroup>
  ```python Python theme={null}
  import asyncio
  from adcp import fetch_adagents, verify_agent_authorization

  async def validate_authorization():
      # Fetch and validate adagents.json from a publisher domain
      adagents_data = await fetch_adagents('example-publisher.com')

      # Check if a specific agent is authorized
      is_authorized = verify_agent_authorization(
          adagents_data=adagents_data,
          agent_url='https://our-sales-agent.com',
          property_type='website',
          property_identifiers=[{'type': 'domain', 'value': 'example-publisher.com'}]
      )

      print(f"Agent authorized: {is_authorized}")
      print(f"Total agents: {len(adagents_data.get('authorized_agents', []))}")

  asyncio.run(validate_authorization())
  ```

  ```javascript JavaScript theme={null}
  // Using the @adcp/client PropertyCrawler for discovery
  import { PropertyCrawler } from '@adcp/client';

  const crawler = new PropertyCrawler({ logLevel: 'info' });

  // Crawl agents to discover their authorized properties
  const result = await crawler.crawlAgents([
    { agent_url: 'https://our-sales-agent.com', protocol: 'a2a' }
  ]);

  console.log(`Found ${result.totalProperties} properties across ${result.totalPublisherDomains} domains`);
  ```

  ```bash CLI theme={null}
  # Fetch and inspect authorization file
  curl https://example-publisher.com/.well-known/adagents.json | jq '.'

  # Check specific agent authorization
  curl https://example-publisher.com/.well-known/adagents.json | \
    jq '.authorized_agents[] | select(.url == "https://our-sales-agent.com")'
  ```
</CodeGroup>

The Python library handles validation automatically when fetching - if the adagents.json file is malformed or missing required fields, it raises `AdagentsValidationError`.

## Best Practices

### 1. Use Appropriate Authorization Pattern

* **Property IDs**: Small, enumerable lists (\< 20 properties)
* **Property Tags**: Large networks (100+ properties)
* **Inline Properties**: Simple cases without top-level properties
* **Publisher Properties**: Third-party agents representing multiple publishers

### 2. Cache Files Appropriately

* Cache for 24 hours minimum
* Use `last_updated` timestamp to detect staleness
* Handle 404 as "no file" (not an error - proceed without validation)
* Implement retry logic with exponential backoff for network errors

### 3. Validate Structure

* Validate against JSON schema before processing
* Check required fields exist (`authorized_agents` array)
* Verify authorization scope matches product claims
* Cross-reference with seller.json if available

### 4. Handle Missing Files Gracefully

* 404 status = No file present (not an authorization failure)
* Absence of file does not mean agent is unauthorized
* Use adagents.json as verification, not requirement

### 5. Handle Per-Property Validation Failures Gracefully

ファイルレベルの失敗（パース不能な JSON、必須のトップレベル `authorized_agents` の欠如）は、そのドメインの処理を中止しなければなりません（MUST）— ファイルは使用不能です。プロパティごとの検証失敗は別の階層です: 他の点では有効なファイル内の単一のプロパティオブジェクトが、パブリッシャー側のテンプレートエラーや部分的な書き込みにより `identifiers` や他の必須フィールドを省略する場合があります。

プロパティごとの検証失敗は、同じファイル内の残りのプロパティの処理を妨げてはなりません（MUST NOT）。非準拠のプロパティを配列から欠けているものとして扱い、決して実行を中止する理由としないでください。

* 非準拠のプロパティを**スキップ**する
* ソースドメイン、配列内のプロパティのインデックス、理由（例: `missing required field: identifiers`）を含む警告を**ログに記録**する
* ファイル内の残りのすべてのプロパティの処理を**続行**する

プロパティごとの失敗で完全なクロールを中止することは、一般的な実装エラーです。数百のパブリッシャードメインをカバーする管理ネットワークファイル内の単一の不正なプロパティが、ディスカバリー実行全体を黙ってゼロにする可能性があり、この失敗モードを基礎となるデータ問題のサイズに対して不釣り合いに破壊的にします。これは、不正な行を無視し後続の行の処理を続行しなければならないと規定する IAB Tech Lab ads.txt 1.1 §3.1 と同じ原則に従います。

これは、プロパティオブジェクトが現れるすべてのサーフェスに適用されます: トップレベル `properties` 配列、`authorized_agents[*].properties` 内のインラインプロパティ（`inline_properties` authorization type）、および `publisher_properties` 解決中にリモートドメインから取得・解決されたプロパティ。

## Next Steps

After implementing adagents.json validation:

1. **Integrate with Product Discovery**: Use [`get_products`](/docs/media-buy/task-reference/get_products) to discover inventory
2. **Validate at Purchase**: Check authorization before calling [`create_media_buy`](/docs/media-buy/task-reference/create_media_buy)
3. **Cache Property Mappings**: Store resolved properties for efficient validation
4. **Monitor Authorization**: Track validation success rates and unauthorized attempts

## Learn More

* [AdCP Basics: Authorized Properties](https://bokonads.com/p/adcp-basics-authorized-properties) - Accessible introduction to AdCP authorization
* [get\_adcp\_capabilities](/docs/protocol/get_adcp_capabilities) - Discover agent capabilities and portfolio
* [Property Schema](https://adcontextprotocol.org/schemas/v2/core/property.json) - Property definition structure
* [AdAgents.json Builder](https://adcontextprotocol.org/adagents) - Web-based validator and creator
