From a8723be98e4b9f57f3d1dc26a5a44fd93799ba29 Mon Sep 17 00:00:00 2001 From: BaiyuScope3 Date: Wed, 24 Dec 2025 17:02:14 -0500 Subject: [PATCH 01/34] feat: add unified assets field for better asset discovery - Add new 'assets' array to format schema with 'required' boolean per asset - Deprecate 'assets_required' (still supported for backward compatibility) - Enables full asset discovery for buyers and AI agents - Update server to include both fields in format responses - Update documentation across creative and media-buy docs - Bump version to 2.6.0 --- CHANGELOG.md | 39 +++++++ docs/creative/asset-types.mdx | 20 +++- docs/creative/formats.mdx | 51 ++++++++- .../creative/implementing-creative-agents.mdx | 4 +- .../task-reference/list_creative_formats.mdx | 4 +- package-lock.json | 4 +- package.json | 2 +- server/src/http.ts | 29 +++-- static/schemas/source/core/format.json | 107 +++++++++++++++++- static/schemas/source/index.json | 2 +- 10 files changed, 237 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ac14daf4f..156ba3729d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,44 @@ # Changelog +## 2.6.0 + +### Minor Changes + +- Add unified `assets` field to format schema for better asset discovery + + **Schema Changes:** + + - **format.json**: Add new `assets` array field that includes both required and optional assets + - **format.json**: Deprecate `assets_required` (still supported for backward compatibility) + + **Rationale:** + + Previously, buyers and AI agents could only see required assets via `assets_required`. There was no way to discover optional assets that enhance creatives (companion banners, third-party tracking pixels, etc.). + + Since each asset already has a `required` boolean field, we introduced a unified `assets` array where: + - `required: true` - Asset MUST be provided for a valid creative + - `required: false` - Asset is optional, enhances the creative when provided + + This enables: + - **Full asset discovery**: Buyers and AI agents can see ALL assets a format supports + - **Richer creatives**: Optional assets like impression trackers can now be discovered and used + - **Cleaner schema**: Single array instead of two separate arrays + + **Example:** + + ```json + { + "format_id": { "agent_url": "https://creative.adcontextprotocol.org", "id": "video_30s" }, + "assets": [ + { "item_type": "individual", "asset_id": "video_file", "asset_type": "video", "required": true }, + { "item_type": "individual", "asset_id": "end_card", "asset_type": "image", "required": false }, + { "item_type": "individual", "asset_id": "impression_tracker", "asset_type": "tracking_pixel", "required": false } + ] + } + ``` + + **Migration:** Non-breaking change. `assets_required` is deprecated but still supported. New implementations should use `assets`. + ## 2.5.1 ### Patch Changes diff --git a/docs/creative/asset-types.mdx b/docs/creative/asset-types.mdx index c3d58aa685..7d669e1a2d 100644 --- a/docs/creative/asset-types.mdx +++ b/docs/creative/asset-types.mdx @@ -338,7 +338,9 @@ The keys in the assets object correspond to the `asset_id` values defined in the ## Usage in Creative Formats -Creative formats specify their required assets using `assets_required` (an array): +Creative formats specify their assets using the `assets` array. Each asset has a `required` boolean: +- **`required: true`** - Asset MUST be provided for a valid creative +- **`required: false`** - Asset is optional, enhances the creative (e.g., companion banners, third-party tracking pixels) ```json { @@ -346,7 +348,7 @@ Creative formats specify their required assets using `assets_required` (an array "agent_url": "https://creative.adcontextprotocol.org", "id": "video_15s_hosted" }, - "assets_required": [ + "assets": [ { "item_type": "individual", "asset_id": "video_file", @@ -359,11 +361,25 @@ Creative formats specify their required assets using `assets_required` (an array "acceptable_resolutions": ["1920x1080", "1280x720"], "max_file_size_mb": 30 } + }, + { + "item_type": "individual", + "asset_id": "impression_tracker", + "asset_type": "tracking_pixel", + "required": false, + "requirements": { + "format": ["url"], + "description": "Third-party impression tracking pixel URL" + } } ] } ``` + +**Backward Compatibility**: The deprecated `assets_required` field is still supported. New implementations should use `assets`. + + ## Repeatable Asset Groups For formats with asset sequences (like carousels, slideshows, stories), see the [Carousel & Multi-Asset Formats guide](/docs/creative/channels/carousels) for complete documentation on repeatable asset group patterns. diff --git a/docs/creative/formats.mdx b/docs/creative/formats.mdx index 882fe96257..be40371c0d 100644 --- a/docs/creative/formats.mdx +++ b/docs/creative/formats.mdx @@ -216,8 +216,9 @@ Formats are JSON objects with the following key fields: }, "name": "30-Second Hosted Video", "type": "video", - "assets_required": [ + "assets": [ { + "item_type": "individual", "asset_id": "video_file", "asset_type": "video", "asset_role": "hero_video", @@ -227,6 +228,39 @@ Formats are JSON objects with the following key fields: "format": ["MP4"], "resolution": ["1920x1080", "1280x720"] } + }, + { + "item_type": "individual", + "asset_id": "end_card_image", + "asset_type": "image", + "asset_role": "end_card", + "required": false, + "requirements": { + "dimensions": "1920x1080", + "format": ["PNG", "JPG"] + } + }, + { + "item_type": "individual", + "asset_id": "companion_banner", + "asset_type": "image", + "asset_role": "companion", + "required": false, + "requirements": { + "dimensions": "300x250", + "format": ["PNG", "JPG", "GIF"] + } + }, + { + "item_type": "individual", + "asset_id": "impression_tracker", + "asset_type": "tracking_pixel", + "asset_role": "third_party_tracking", + "required": false, + "requirements": { + "format": ["url"], + "description": "Third-party impression tracking pixel URL" + } } ] } @@ -236,10 +270,23 @@ Formats are JSON objects with the following key fields: - **format_id**: Unique identifier (may be namespaced with `domain:id`) - **agent_url**: The creative agent authoritative for this format - **type**: Category (video, display, audio, native, dooh, rich_media) -- **assets_required**: Array of asset specifications +- **assets**: Array of all asset specifications with `required` boolean indicating mandatory vs optional - **asset_role**: Identifies asset purpose (hero_image, logo, cta_button, etc.) - **renders**: Array of rendered outputs with dimensions - see below +### Asset Discovery + +The `assets` array enables comprehensive asset discovery. Each asset has a `required` boolean: + +- **`required: true`** - Asset MUST be provided for a valid creative +- **`required: false`** - Asset is optional, enhances the creative when provided (e.g., companion banners, third-party tracking pixels) + +This unified approach helps creative tools and AI agents understand the full capabilities of a format, enabling richer creative experiences when optional assets are available while clearly indicating minimum requirements. + + +**Backward Compatibility**: The deprecated `assets_required` field is still supported for existing implementations. New implementations should use `assets` with the `required` boolean on each asset. + + ### Rendered Outputs and Dimensions Formats specify their rendered outputs via the `renders` array. Most formats produce a single render, but some (companion ads, adaptive formats, multi-placement) produce multiple renders: diff --git a/docs/creative/implementing-creative-agents.mdx b/docs/creative/implementing-creative-agents.mdx index 98671f1eb2..dea73b1478 100644 --- a/docs/creative/implementing-creative-agents.mdx +++ b/docs/creative/implementing-creative-agents.mdx @@ -100,7 +100,7 @@ Creative agents must implement these two tasks: Return all formats your agent defines. This is how buyers discover what creative formats you support. **Key responsibilities:** -- Return complete format definitions with all `assets_required` +- Return complete format definitions with all `assets` (both required and optional) - Include your `agent_url` in each format - Use proper namespacing for `format_id` values @@ -169,7 +169,7 @@ When validating manifests: When updating format definitions: -- **Additive changes** (new optional assets) are safe +- **Additive changes** (new optional assets in `assets_optional`) are safe - **Breaking changes** (removing assets, changing requirements) require new format_id - Consider versioning: `youragency.com:format_name_v2` - Maintain backward compatibility when possible diff --git a/docs/media-buy/task-reference/list_creative_formats.mdx b/docs/media-buy/task-reference/list_creative_formats.mdx index f5f7ed11f3..30c4ba1b58 100644 --- a/docs/media-buy/task-reference/list_creative_formats.mdx +++ b/docs/media-buy/task-reference/list_creative_formats.mdx @@ -40,7 +40,7 @@ Formats may produce multiple rendered pieces (e.g., video + companion banner). D | Field | Description | |-------|-------------| -| `formats` | Array of full format definitions (format_id, name, type, requirements, assets_required, renders) | +| `formats` | Array of full format definitions (format_id, name, type, requirements, assets, renders) | | `creative_agents` | Optional array of other creative agents providing additional formats | See [Format schema](https://adcontextprotocol.org/schemas/v2/core/format.json) for complete format object structure. @@ -405,7 +405,7 @@ Each format includes: | `name` | Human-readable format name | | `type` | Format type (audio, video, display, dooh) | | `requirements` | Technical requirements (duration, file types, bitrate, etc.) | -| `assets_required` | Array of required assets with specifications | +| `assets` | Array of all assets with `required` boolean indicating mandatory vs optional | | `renders` | Array of rendered output pieces (dimensions, role) | ### Asset Roles diff --git a/package-lock.json b/package-lock.json index db95e22227..31742dbfb8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "adcontextprotocol", - "version": "2.5.0", + "version": "2.5.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "adcontextprotocol", - "version": "2.5.0", + "version": "2.5.2", "dependencies": { "@adcp/client": "^3.4.0", "@modelcontextprotocol/sdk": "^1.24.3", diff --git a/package.json b/package.json index 0ec58a9540..91ded87e56 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "adcontextprotocol", - "version": "2.5.1", + "version": "2.6.0", "private": true, "scripts": { "start": "bash -c 'source <(grep CONDUCTOR_PORT .env.local | sed \"s/^/export /\") && DOTENV_CONFIG_PATH=.env.local PORT=${CONDUCTOR_PORT:-3000} tsx watch server/src/index.ts'", diff --git a/server/src/http.ts b/server/src/http.ts index 3b9718d96d..fbcbe426cd 100644 --- a/server/src/http.ts +++ b/server/src/http.ts @@ -8334,18 +8334,23 @@ Disallow: /api/admin/ return res.json({ success: true, - formats: formats.map(format => ({ - format_id: format.format_id, - name: format.name, - type: format.type, - description: format.description, - preview_image: format.preview_image, - example_url: format.example_url, - renders: format.renders, - assets_required: format.assets_required, - output_format_ids: format.output_format_ids, - agent_url: format.agent_url, - })), + formats: formats.map(format => { + // Cast to allow 'assets' field (added in schema v2.5.2, @adcp/client may not have it yet) + const formatWithAssets = format as typeof format & { assets?: unknown }; + return { + format_id: format.format_id, + name: format.name, + type: format.type, + description: format.description, + preview_image: format.preview_image, + example_url: format.example_url, + renders: format.renders, + assets_required: format.assets_required, // deprecated but kept for backward compatibility + assets: formatWithAssets.assets, // new unified field + output_format_ids: format.output_format_ids, + agent_url: format.agent_url, + }; + }), }); } catch (error) { logger.error({ err: error, url }, 'Agent formats fetch error'); diff --git a/static/schemas/source/core/format.json b/static/schemas/source/core/format.json index d778d5de8c..b399d24cef 100644 --- a/static/schemas/source/core/format.json +++ b/static/schemas/source/core/format.json @@ -121,7 +121,7 @@ }, "assets_required": { "type": "array", - "description": "Array of required assets or asset groups for this format. Each asset is identified by its asset_id, which must be used as the key in creative manifests. Can contain individual assets or repeatable asset sequences (e.g., carousel products, slideshow frames).", + "description": "DEPRECATED: Use 'assets' instead. Array of required assets or asset groups for this format. Each asset is identified by its asset_id, which must be used as the key in creative manifests. Can contain individual assets or repeatable asset sequences (e.g., carousel products, slideshow frames). This field is maintained for backward compatibility; new implementations should use 'assets' with the 'required' boolean on each asset.", "items": { "oneOf": [ { @@ -217,6 +217,111 @@ ] } }, + "assets": { + "type": "array", + "description": "Array of all assets supported for this format. Each asset is identified by its asset_id, which must be used as the key in creative manifests. Use the 'required' boolean on each asset to indicate whether it's mandatory. This field replaces the deprecated 'assets_required' and enables full asset discovery for buyers and AI agents.", + "items": { + "oneOf": [ + { + "description": "Individual asset specification", + "type": "object", + "properties": { + "item_type": { + "type": "string", + "const": "individual", + "description": "Discriminator indicating this is an individual asset" + }, + "asset_id": { + "type": "string", + "description": "Unique identifier for this asset. Creative manifests MUST use this exact value as the key in the assets object." + }, + "asset_type": { + "$ref": "/schemas/enums/asset-content-type.json", + "description": "Type of asset" + }, + "asset_role": { + "type": "string", + "description": "Optional descriptive label for this asset's purpose (e.g., 'hero_image', 'logo', 'third_party_tracking'). Not used for referencing assets in manifests—use asset_id instead. This field is for human-readable documentation and UI display only." + }, + "required": { + "type": "boolean", + "description": "Whether this asset is required (true) or optional (false). Required assets must be provided for a valid creative. Optional assets enhance the creative but are not mandatory.", + "default": false + }, + "requirements": { + "type": "object", + "description": "Technical requirements for this asset (dimensions, file size, duration, etc.). For template formats, use parameters_from_format_id: true to indicate asset parameters must match the format_id parameters (width/height/unit and/or duration_ms).", + "additionalProperties": true + } + }, + "required": ["item_type", "asset_id", "asset_type"] + }, + { + "description": "Repeatable asset group (for carousels, slideshows, playlists, etc.)", + "type": "object", + "properties": { + "item_type": { + "type": "string", + "const": "repeatable_group", + "description": "Discriminator indicating this is a repeatable asset group" + }, + "asset_group_id": { + "type": "string", + "description": "Identifier for this asset group (e.g., 'product', 'slide', 'card')" + }, + "required": { + "type": "boolean", + "description": "Whether this asset group is required. If true, at least min_count repetitions must be provided.", + "default": false + }, + "min_count": { + "type": "integer", + "description": "Minimum number of repetitions required (if group is required) or allowed (if optional)", + "minimum": 0 + }, + "max_count": { + "type": "integer", + "description": "Maximum number of repetitions allowed", + "minimum": 1 + }, + "assets": { + "type": "array", + "description": "Assets within each repetition of this group", + "items": { + "type": "object", + "properties": { + "asset_id": { + "type": "string", + "description": "Identifier for this asset within the group" + }, + "asset_type": { + "$ref": "/schemas/enums/asset-content-type.json", + "description": "Type of asset" + }, + "asset_role": { + "type": "string", + "description": "Optional descriptive label for this asset's purpose. Not used for referencing assets in manifests—use asset_id instead. This field is for human-readable documentation and UI display only." + }, + "required": { + "type": "boolean", + "description": "Whether this asset is required within each repetition of the group", + "default": false + }, + "requirements": { + "type": "object", + "description": "Technical requirements for this asset. For template formats, use parameters_from_format_id: true to indicate asset parameters must match the format_id parameters (width/height/unit and/or duration_ms).", + "additionalProperties": true + } + }, + "required": ["asset_id", "asset_type"] + } + } + }, + "required": ["item_type", "asset_group_id", "min_count", "max_count", "assets"] + } + ] + } + }, "delivery": { "type": "object", "description": "Delivery method specifications (e.g., hosted, VAST, third-party tags)", diff --git a/static/schemas/source/index.json b/static/schemas/source/index.json index 2056c90cee..6ea9e42a77 100644 --- a/static/schemas/source/index.json +++ b/static/schemas/source/index.json @@ -4,7 +4,7 @@ "title": "AdCP Schema Registry v1", "version": "1.0.0", "description": "Registry of all AdCP JSON schemas for validation and discovery", - "adcp_version": "2.5.1", + "adcp_version": "2.6.0", "standard_formats_version": "2.0.0", "versioning": { "note": "AdCP uses path-based versioning. The schema URL path (/schemas/) indicates the version. Individual request/response schemas do NOT include adcp_version fields. Compatibility follows semantic versioning rules." From e2b0b62364f4fd9dfc7894d14cf7bb52eeb74243 Mon Sep 17 00:00:00 2001 From: BaiyuScope3 Date: Fri, 2 Jan 2026 14:57:17 -0500 Subject: [PATCH 02/34] Add changeset for assets field feature --- .changeset/assets-discovery.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .changeset/assets-discovery.md diff --git a/.changeset/assets-discovery.md b/.changeset/assets-discovery.md new file mode 100644 index 0000000000..43d94fd6e9 --- /dev/null +++ b/.changeset/assets-discovery.md @@ -0,0 +1,11 @@ +--- +"adcontextprotocol": minor +--- + +Add unified `assets` field to format schema for better asset discovery + +- Add new `assets` array to format schema with `required` boolean per asset +- Deprecate `assets_required` (still supported for backward compatibility) +- Enables full asset discovery for buyers and AI agents to see all supported assets +- Optional assets like impression trackers can now be discovered and used + From e4ed83965e62060ed3231f2f6cfa2e88061fa373 Mon Sep 17 00:00:00 2001 From: BaiyuScope3 Date: Fri, 2 Jan 2026 15:02:11 -0500 Subject: [PATCH 03/34] fix: update CI to use .cjs extension for check-testable-snippets --- .github/workflows/check-testable-snippets.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check-testable-snippets.yml b/.github/workflows/check-testable-snippets.yml index 7dea6c929c..e3ef8c2785 100644 --- a/.github/workflows/check-testable-snippets.yml +++ b/.github/workflows/check-testable-snippets.yml @@ -26,7 +26,7 @@ jobs: if [ -s changed_files.txt ]; then echo "📋 Checking documentation changes for testable snippets..." - node scripts/check-testable-snippets.js + node scripts/check-testable-snippets.cjs else echo "✓ No documentation files changed" fi From e7bbaac17bdf2813a028b89c776e2b99bbbd8e02 Mon Sep 17 00:00:00 2001 From: BaiyuScope3 Date: Fri, 2 Jan 2026 15:15:54 -0500 Subject: [PATCH 04/34] fix: update docs to reference assets field instead of assets_optional --- docs/creative/implementing-creative-agents.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/creative/implementing-creative-agents.mdx b/docs/creative/implementing-creative-agents.mdx index dea73b1478..abb86bb5d0 100644 --- a/docs/creative/implementing-creative-agents.mdx +++ b/docs/creative/implementing-creative-agents.mdx @@ -169,7 +169,7 @@ When validating manifests: When updating format definitions: -- **Additive changes** (new optional assets in `assets_optional`) are safe +- **Additive changes** (new optional assets with `required: false` in `assets`) are safe - **Breaking changes** (removing assets, changing requirements) require new format_id - Consider versioning: `youragency.com:format_name_v2` - Maintain backward compatibility when possible From 619ca3e7f3492a55189e7ca49a6602973db5130b Mon Sep 17 00:00:00 2001 From: BaiyuScope3 Date: Fri, 2 Jan 2026 16:36:52 -0500 Subject: [PATCH 05/34] docs: keep assets_required as deprecated alongside new assets field --- docs/creative/asset-types.mdx | 2 +- docs/creative/formats.mdx | 3 ++- docs/creative/task-reference/list_creative_formats.mdx | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/creative/asset-types.mdx b/docs/creative/asset-types.mdx index b4a4cdbac4..32ba29a231 100644 --- a/docs/creative/asset-types.mdx +++ b/docs/creative/asset-types.mdx @@ -377,7 +377,7 @@ Creative formats specify their assets using the `assets` array. Each asset has a ``` -**Backward Compatibility**: The deprecated `assets_required` field is still supported. New implementations should use `assets`. +**Backward Compatibility**: The `assets_required` field is deprecated but still supported. Existing implementations can continue using `assets_required` for required assets only. New implementations should use `assets` with the `required` boolean for full asset discovery. ## Repeatable Asset Groups diff --git a/docs/creative/formats.mdx b/docs/creative/formats.mdx index 15470c3b6f..d3fb20715e 100644 --- a/docs/creative/formats.mdx +++ b/docs/creative/formats.mdx @@ -276,6 +276,7 @@ Formats are JSON objects with the following key fields: - **agent_url**: The creative agent authoritative for this format - **type**: Category (video, display, audio, native, dooh, rich_media) - **assets**: Array of all asset specifications with `required` boolean indicating mandatory vs optional +- **assets_required**: *(Deprecated)* Array of required asset specifications - use `assets` instead - **asset_role**: Identifies asset purpose (hero_image, logo, cta_button, etc.) - **renders**: Array of rendered outputs with dimensions - see below @@ -289,7 +290,7 @@ The `assets` array enables comprehensive asset discovery. Each asset has a `requ This unified approach helps creative tools and AI agents understand the full capabilities of a format, enabling richer creative experiences when optional assets are available while clearly indicating minimum requirements. -**Backward Compatibility**: The deprecated `assets_required` field is still supported for existing implementations. New implementations should use `assets` with the `required` boolean on each asset. +**Backward Compatibility**: The `assets_required` field is deprecated but still supported. Existing implementations can continue using `assets_required` for required assets only. New implementations should use `assets` with the `required` boolean on each asset for full asset discovery. ### Rendered Outputs and Dimensions diff --git a/docs/creative/task-reference/list_creative_formats.mdx b/docs/creative/task-reference/list_creative_formats.mdx index cc22e2b296..af0348f718 100644 --- a/docs/creative/task-reference/list_creative_formats.mdx +++ b/docs/creative/task-reference/list_creative_formats.mdx @@ -56,7 +56,7 @@ Formats may produce multiple rendered pieces (e.g., video + companion banner). D | Field | Description | |-------|-------------| -| `formats` | Array of full format definitions (format_id, name, type, requirements, assets, renders) | +| `formats` | Array of full format definitions (format_id, name, type, requirements, assets, assets_required, renders) | | `creative_agents` | Optional array of other creative agents providing additional formats | See [Format schema](https://adcontextprotocol.org/schemas/v2/core/format.json) for complete format object structure. @@ -422,6 +422,7 @@ Each format includes: | `type` | Format type (audio, video, display, dooh) | | `requirements` | Technical requirements (duration, file types, bitrate, etc.) | | `assets` | Array of all assets with `required` boolean indicating mandatory vs optional | +| `assets_required` | *(Deprecated)* Array of required assets - use `assets` instead | | `renders` | Array of rendered output pieces (dimensions, role) | ### Asset Roles From 7681bfb4982908d97ed44ad4ec48133503371f1c Mon Sep 17 00:00:00 2001 From: BaiyuScope3 Date: Fri, 2 Jan 2026 16:38:27 -0500 Subject: [PATCH 06/34] schema: add formal deprecated: true to assets_required field --- static/schemas/source/core/format.json | 1 + 1 file changed, 1 insertion(+) diff --git a/static/schemas/source/core/format.json b/static/schemas/source/core/format.json index b399d24cef..9ab38f749c 100644 --- a/static/schemas/source/core/format.json +++ b/static/schemas/source/core/format.json @@ -121,6 +121,7 @@ }, "assets_required": { "type": "array", + "deprecated": true, "description": "DEPRECATED: Use 'assets' instead. Array of required assets or asset groups for this format. Each asset is identified by its asset_id, which must be used as the key in creative manifests. Can contain individual assets or repeatable asset sequences (e.g., carousel products, slideshow frames). This field is maintained for backward compatibility; new implementations should use 'assets' with the 'required' boolean on each asset.", "items": { "oneOf": [ From 0bbdf287021976be9ea577d1d28683529ee504c8 Mon Sep 17 00:00:00 2001 From: BaiyuScope3 Date: Fri, 2 Jan 2026 16:42:08 -0500 Subject: [PATCH 07/34] schema: make 'required' field mandatory in assets array --- static/schemas/source/core/format.json | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/static/schemas/source/core/format.json b/static/schemas/source/core/format.json index 9ab38f749c..5e6330740c 100644 --- a/static/schemas/source/core/format.json +++ b/static/schemas/source/core/format.json @@ -246,8 +246,7 @@ }, "required": { "type": "boolean", - "description": "Whether this asset is required (true) or optional (false). Required assets must be provided for a valid creative. Optional assets enhance the creative but are not mandatory.", - "default": false + "description": "Whether this asset is required (true) or optional (false). Required assets must be provided for a valid creative. Optional assets enhance the creative but are not mandatory." }, "requirements": { "type": "object", @@ -255,7 +254,7 @@ "additionalProperties": true } }, - "required": ["item_type", "asset_id", "asset_type"] + "required": ["item_type", "asset_id", "asset_type", "required"] }, { "description": "Repeatable asset group (for carousels, slideshows, playlists, etc.)", @@ -272,8 +271,7 @@ }, "required": { "type": "boolean", - "description": "Whether this asset group is required. If true, at least min_count repetitions must be provided.", - "default": false + "description": "Whether this asset group is required. If true, at least min_count repetitions must be provided." }, "min_count": { "type": "integer", @@ -318,7 +316,7 @@ } } }, - "required": ["item_type", "asset_group_id", "min_count", "max_count", "assets"] + "required": ["item_type", "asset_group_id", "required", "min_count", "max_count", "assets"] } ] } From c8a4487b1af8b8e4162cd35d8e33857c778cb50c Mon Sep 17 00:00:00 2001 From: BaiyuScope3 Date: Fri, 2 Jan 2026 16:45:36 -0500 Subject: [PATCH 08/34] schema: make 'required' field mandatory in nested repeatable_group assets --- static/schemas/source/core/format.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/schemas/source/core/format.json b/static/schemas/source/core/format.json index 5e6330740c..a018252ddc 100644 --- a/static/schemas/source/core/format.json +++ b/static/schemas/source/core/format.json @@ -312,7 +312,7 @@ "additionalProperties": true } }, - "required": ["asset_id", "asset_type"] + "required": ["asset_id", "asset_type", "required"] } } }, From 8261125d9e20c954c24c26b451f5fb8cf6d92f89 Mon Sep 17 00:00:00 2001 From: BaiyuScope3 Date: Fri, 2 Jan 2026 17:24:34 -0500 Subject: [PATCH 09/34] docs: add deprecated assets_required examples with deprecation comments --- docs/creative/asset-types.mdx | 16 ++++++++++++++++ docs/creative/formats.mdx | 15 +++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/docs/creative/asset-types.mdx b/docs/creative/asset-types.mdx index 32ba29a231..927fbedf1f 100644 --- a/docs/creative/asset-types.mdx +++ b/docs/creative/asset-types.mdx @@ -372,6 +372,22 @@ Creative formats specify their assets using the `assets` array. Each asset has a "description": "Third-party impression tracking pixel URL" } } + ], + + // DEPRECATED: Use "assets" above instead. Kept for backward compatibility. + "assets_required": [ + { + "item_type": "individual", + "asset_id": "video_file", + "asset_type": "video", + "requirements": { + "duration_seconds": 15, + "acceptable_formats": ["mp4"], + "acceptable_codecs": ["h264"], + "acceptable_resolutions": ["1920x1080", "1280x720"], + "max_file_size_mb": 30 + } + } ] } ``` diff --git a/docs/creative/formats.mdx b/docs/creative/formats.mdx index d3fb20715e..ba6b100d4f 100644 --- a/docs/creative/formats.mdx +++ b/docs/creative/formats.mdx @@ -267,6 +267,21 @@ Formats are JSON objects with the following key fields: "description": "Third-party impression tracking pixel URL" } } + ], + + // DEPRECATED: Use "assets" above instead. Kept for backward compatibility. + "assets_required": [ + { + "item_type": "individual", + "asset_id": "video_file", + "asset_type": "video", + "asset_role": "hero_video", + "requirements": { + "duration": "30s", + "format": ["MP4"], + "resolution": ["1920x1080", "1280x720"] + } + } ] } ``` From 7c9c9f9b5ac55b9116e9de525dfaf9427472d682 Mon Sep 17 00:00:00 2001 From: BaiyuScope3 Date: Fri, 2 Jan 2026 17:30:32 -0500 Subject: [PATCH 10/34] ci: add 2.6.x branch to all workflows --- .github/workflows/broken-links.yml | 4 ++-- .github/workflows/changeset-check.yml | 2 +- .github/workflows/check-testable-snippets.yml | 1 + .github/workflows/release.yml | 1 + .github/workflows/schema-validation.yml | 4 ++-- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/broken-links.yml b/.github/workflows/broken-links.yml index b8b2bce77e..8b3045af7e 100644 --- a/.github/workflows/broken-links.yml +++ b/.github/workflows/broken-links.yml @@ -2,9 +2,9 @@ name: Check for Broken Links on: push: - branches: [ main, develop ] + branches: [ main, develop, '2.6.x' ] pull_request: - branches: [ main, develop ] + branches: [ main, develop, '2.6.x' ] jobs: broken-links: diff --git a/.github/workflows/changeset-check.yml b/.github/workflows/changeset-check.yml index 346ed6202c..267de5f1f6 100644 --- a/.github/workflows/changeset-check.yml +++ b/.github/workflows/changeset-check.yml @@ -2,7 +2,7 @@ name: Changeset Check on: pull_request: - branches: [main] + branches: [main, '2.6.x'] jobs: check: diff --git a/.github/workflows/check-testable-snippets.yml b/.github/workflows/check-testable-snippets.yml index e3ef8c2785..f28614b7da 100644 --- a/.github/workflows/check-testable-snippets.yml +++ b/.github/workflows/check-testable-snippets.yml @@ -2,6 +2,7 @@ name: Check Testable Snippets on: pull_request: + branches: [main, '2.6.x'] paths: - 'docs/**/*.md' - 'docs/**/*.mdx' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c5665ce6d3..176da7a247 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,6 +4,7 @@ on: push: branches: - main + - '2.6.x' concurrency: ${{ github.workflow }}-${{ github.ref }} diff --git a/.github/workflows/schema-validation.yml b/.github/workflows/schema-validation.yml index 7d772503ff..a599e1adb5 100644 --- a/.github/workflows/schema-validation.yml +++ b/.github/workflows/schema-validation.yml @@ -2,9 +2,9 @@ name: JSON Schema Validation on: push: - branches: [ main, develop ] + branches: [ main, develop, '2.6.x' ] pull_request: - branches: [ main, develop ] + branches: [ main, develop, '2.6.x' ] jobs: schema-validation: From dba91d112e64119ea02a616ab80f7873f901ceff Mon Sep 17 00:00:00 2001 From: BaiyuScope3 Date: Mon, 5 Jan 2026 14:36:25 -0500 Subject: [PATCH 11/34] docs: update intro and schema-versioning for 2.6.0 --- docs/intro.mdx | 4 ++-- docs/reference/schema-versioning.mdx | 28 ++++++++++++++-------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/intro.mdx b/docs/intro.mdx index 7ec71cf192..fa5dd7389a 100644 --- a/docs/intro.mdx +++ b/docs/intro.mdx @@ -7,9 +7,9 @@ keywords: [advertising automation protocol, programmatic advertising API, MCP ad -**🎉 AdCP v2.5.0 Released** +**🎉 AdCP v2.6.0 Released** -Developer experience and API refinement release featuring type safety improvements, batch creative previews (5-10x faster), schema versioning (`/schemas/v2.5/`), template formats with dynamic sizing, enhanced product filtering, and inline creative updates. [See what's new →](/docs/reference/release-notes) +Asset discovery release featuring unified `assets` field in format schema for discovering both required and optional assets. Buyers and AI agents can now see ALL assets a format supports. [See what's new →](/docs/reference/release-notes) Welcome to the Ad Context Protocol (AdCP) documentation. AdCP is an **open standard for advertising automation** that enables AI assistants to interact with advertising platforms through unified, standardized interfaces. diff --git a/docs/reference/schema-versioning.mdx b/docs/reference/schema-versioning.mdx index 8c11d4606e..7b979d3ffd 100644 --- a/docs/reference/schema-versioning.mdx +++ b/docs/reference/schema-versioning.mdx @@ -21,7 +21,7 @@ All AdCP schemas are available at multiple paths: ### Exact Version (Recommended for Production) ``` -/schemas/2.5.0/core/product.json +/schemas/2.6.0/core/product.json ``` - **Pin to specific release** - URL never changes - **Guaranteed stability** - Schema won't update unexpectedly @@ -69,8 +69,8 @@ Bundled schemas are experimental and may change or be removed in future releases For tools that don't support `$ref` resolution (some API clients, code generators, or desktop applications), AdCP provides **bundled schemas** with all references resolved inline: ``` -/schemas/2.5.0/bundled/media-buy/create-media-buy-request.json -/schemas/2.5.0/bundled/media-buy/get-products-response.json +/schemas/2.6.0/bundled/media-buy/create-media-buy-request.json +/schemas/2.6.0/bundled/media-buy/get-products-response.json ``` ### What's Bundled @@ -91,11 +91,11 @@ Bundled schemas are generated for all request/response schemas (`*-request.json` ```javascript // Bundled - self-contained, no ref resolution needed -const schema = await fetch('https://adcp.org/schemas/2.5.0/bundled/media-buy/create-media-buy-request.json'); +const schema = await fetch('https://adcp.org/schemas/2.6.0/bundled/media-buy/create-media-buy-request.json'); const validate = ajv.compile(await schema.json()); // Modular - requires $ref resolution -const schema = await fetch('https://adcp.org/schemas/2.5.0/media-buy/create-media-buy-request.json'); +const schema = await fetch('https://adcp.org/schemas/2.6.0/media-buy/create-media-buy-request.json'); // This schema contains $ref to other schemas that must be resolved ``` @@ -105,7 +105,7 @@ Bundled schemas include a `_bundled` field with generation metadata: ```json { - "$id": "/schemas/2.5.0/bundled/core/product.json", + "$id": "/schemas/2.6.0/bundled/core/product.json", "title": "Product", "_bundled": { "generatedAt": "2024-12-17T10:30:00.000Z", @@ -120,7 +120,7 @@ Bundled schemas include a `_bundled` field with generation metadata: ```javascript // Production - pin exact version -const SCHEMA_VERSION = '2.5.0'; +const SCHEMA_VERSION = '2.6.0'; const schema = await fetch(`https://adcp.org/schemas/${SCHEMA_VERSION}/core/product.json`); // Stable development - track minor version (patch updates only) @@ -137,12 +137,12 @@ Always use exact versions to ensure generated types match your target protocol v ```bash # TypeScript SDK generation npx json-schema-to-typescript \ - https://adcp.org/schemas/2.5.0/core/product.json \ + https://adcp.org/schemas/2.6.0/core/product.json \ --output types/product.d.ts # Python SDK generation datamodel-codegen \ - --url https://adcp.org/schemas/2.5.0/core/product.json \ + --url https://adcp.org/schemas/2.6.0/core/product.json \ --output models/product.py ``` @@ -153,7 +153,7 @@ datamodel-codegen \ import Ajv from 'ajv'; const ajv = new Ajv(); -const schema = await fetch('https://adcp.org/schemas/2.5.0/core/product.json'); +const schema = await fetch('https://adcp.org/schemas/2.6.0/core/product.json'); const validate = ajv.compile(await schema.json()); if (!validate(data)) { @@ -227,7 +227,7 @@ If you're currently using `/schemas/v2/`: ``` 3. **Consider pinning** for production stability: ```javascript - const schema = await fetch('/schemas/2.5.0/core/product.json'); + const schema = await fetch('/schemas/2.6.0/core/product.json'); ``` ### From Exact Version to Major Alias @@ -270,11 +270,11 @@ If you want to track the latest 2.x: ```bash # Get schema registry with version info curl https://adcp.org/schemas/v2/index.json | jq '.adcp_version' -# Output: "2.5.0" +# Output: "2.6.0" # Get version from specific release -curl https://adcp.org/schemas/2.5.0/index.json | jq '.adcp_version' -# Output: "2.5.0" +curl https://adcp.org/schemas/2.6.0/index.json | jq '.adcp_version' +# Output: "2.6.0" ``` ### List Available Versions From 8a3e2c4987c147770490c0f02cbc5b23aff27c74 Mon Sep 17 00:00:00 2001 From: BaiyuScope3 Date: Mon, 5 Jan 2026 14:51:39 -0500 Subject: [PATCH 12/34] fix: detect untracked files in sync-versioned-docs workflow git diff only detects tracked files. Use git add + git diff --cached to properly detect new v2.6-rc/ folder on first sync. --- .github/workflows/sync-versioned-docs.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/sync-versioned-docs.yml b/.github/workflows/sync-versioned-docs.yml index 62819dc076..3a15e4bec3 100644 --- a/.github/workflows/sync-versioned-docs.yml +++ b/.github/workflows/sync-versioned-docs.yml @@ -38,8 +38,9 @@ jobs: # Extract docs folder from 2.6.x branch git archive origin/2.6.x -- docs | tar -x -C v2.6-rc/ - # Check if there are changes - if git diff --quiet v2.6-rc/; then + # Check if there are changes (including untracked files) + git add v2.6-rc/ + if git diff --cached --quiet; then echo "No changes to sync" echo "CHANGES_DETECTED=false" >> $GITHUB_ENV else From d7677307248d2bb41d70dace9ffcf0087f9ebc82 Mon Sep 17 00:00:00 2001 From: BaiyuScope3 Date: Mon, 5 Jan 2026 14:57:40 -0500 Subject: [PATCH 13/34] fix: create PR instead of pushing directly to main Main branch is protected. Use peter-evans/create-pull-request action to create a PR for the synced docs instead of direct push. --- .github/workflows/sync-versioned-docs.yml | 36 +++++++++-------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/.github/workflows/sync-versioned-docs.yml b/.github/workflows/sync-versioned-docs.yml index 3a15e4bec3..e22cd7dfe7 100644 --- a/.github/workflows/sync-versioned-docs.yml +++ b/.github/workflows/sync-versioned-docs.yml @@ -21,11 +21,6 @@ jobs: fetch-depth: 0 token: ${{ secrets.GITHUB_TOKEN }} - - name: Configure Git - run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - - name: Fetch 2.6.x branch run: git fetch origin 2.6.x @@ -38,20 +33,17 @@ jobs: # Extract docs folder from 2.6.x branch git archive origin/2.6.x -- docs | tar -x -C v2.6-rc/ - # Check if there are changes (including untracked files) - git add v2.6-rc/ - if git diff --cached --quiet; then - echo "No changes to sync" - echo "CHANGES_DETECTED=false" >> $GITHUB_ENV - else - echo "Changes detected in v2.6-rc docs" - echo "CHANGES_DETECTED=true" >> $GITHUB_ENV - fi - - - name: Commit and push changes - if: env.CHANGES_DETECTED == 'true' - run: | - git add v2.6-rc/ - git commit -m "chore: sync v2.6-rc docs from 2.6.x branch [skip ci]" - git push origin main - + - name: Create Pull Request + uses: peter-evans/create-pull-request@v7 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: "chore: sync v2.6-rc docs from 2.6.x branch" + title: "chore: sync v2.6-rc docs from 2.6.x branch" + body: | + This PR syncs the v2.6-rc documentation from the 2.6.x branch. + + Auto-generated by the sync-versioned-docs workflow. + branch: auto/sync-v2.6-rc-docs + delete-branch: true + add-paths: | + v2.6-rc/ From fcb13f2b740749df1ebf656068935620f84e1c56 Mon Sep 17 00:00:00 2001 From: BaiyuScope3 Date: Wed, 7 Jan 2026 14:58:15 -0500 Subject: [PATCH 14/34] chore: regenerate dist/schemas/2.6.0 with additionalProperties: true Rebuilds 2.6.0 schemas to include the relaxed validation from #646. All schema objects now allow unknown fields for forward compatibility. --- dist/schemas/2.6.0/adagents.json | 480 ++++++++++-------- .../media-buy/build-creative-request.json | 54 +- .../media-buy/build-creative-response.json | 60 +-- .../media-buy/create-media-buy-request.json | 68 +-- .../media-buy/create-media-buy-response.json | 24 +- .../get-media-buy-delivery-request.json | 6 +- .../get-media-buy-delivery-response.json | 28 +- .../media-buy/get-products-request.json | 18 +- .../media-buy/get-products-response.json | 66 +-- .../list-authorized-properties-request.json | 6 +- .../list-authorized-properties-response.json | 12 +- .../list-creative-formats-request.json | 8 +- .../list-creative-formats-response.json | 26 +- .../media-buy/list-creatives-request.json | 12 +- .../media-buy/list-creatives-response.json | 66 +-- .../bundled/media-buy/package-request.json | 58 +-- .../provide-performance-feedback-request.json | 8 +- ...provide-performance-feedback-response.json | 14 +- .../media-buy/sync-creatives-request.json | 54 +- .../media-buy/sync-creatives-response.json | 18 +- .../media-buy/update-media-buy-request.json | 60 +-- .../media-buy/update-media-buy-response.json | 24 +- .../signals/activate-signal-request.json | 10 +- .../signals/activate-signal-response.json | 26 +- .../bundled/signals/get-signals-request.json | 14 +- .../bundled/signals/get-signals-response.json | 28 +- dist/schemas/2.6.0/core/activation-key.json | 15 +- .../2.6.0/core/assets/audio-asset.json | 6 +- dist/schemas/2.6.0/core/assets/css-asset.json | 6 +- .../2.6.0/core/assets/daast-asset.json | 14 +- .../schemas/2.6.0/core/assets/html-asset.json | 6 +- .../2.6.0/core/assets/image-asset.json | 8 +- .../2.6.0/core/assets/javascript-asset.json | 6 +- .../2.6.0/core/assets/markdown-asset.json | 6 +- .../schemas/2.6.0/core/assets/text-asset.json | 6 +- dist/schemas/2.6.0/core/assets/url-asset.json | 6 +- .../schemas/2.6.0/core/assets/vast-asset.json | 14 +- .../2.6.0/core/assets/video-asset.json | 8 +- .../2.6.0/core/assets/webhook-asset.json | 12 +- .../2.6.0/core/async-response-data.json | 1 - dist/schemas/2.6.0/core/brand-manifest.json | 185 ++++--- dist/schemas/2.6.0/core/creative-asset.json | 67 ++- .../2.6.0/core/creative-assignment.json | 8 +- dist/schemas/2.6.0/core/creative-filters.json | 2 +- .../schemas/2.6.0/core/creative-manifest.json | 4 +- dist/schemas/2.6.0/core/creative-policy.json | 10 +- dist/schemas/2.6.0/core/delivery-metrics.json | 9 +- dist/schemas/2.6.0/core/deployment.json | 16 +- dist/schemas/2.6.0/core/destination.json | 14 +- dist/schemas/2.6.0/core/error.json | 13 +- dist/schemas/2.6.0/core/format-id.json | 15 +- dist/schemas/2.6.0/core/format.json | 90 +++- dist/schemas/2.6.0/core/frequency-cap.json | 8 +- .../2.6.0/core/mcp-webhook-payload.json | 7 +- dist/schemas/2.6.0/core/measurement.json | 31 +- dist/schemas/2.6.0/core/media-buy.json | 2 +- dist/schemas/2.6.0/core/package.json | 2 +- .../2.6.0/core/performance-feedback.json | 18 +- dist/schemas/2.6.0/core/placement.json | 7 +- dist/schemas/2.6.0/core/product-filters.json | 20 +- dist/schemas/2.6.0/core/product.json | 6 +- .../2.6.0/core/promoted-offerings.json | 42 +- .../schemas/2.6.0/core/promoted-products.json | 16 +- dist/schemas/2.6.0/core/property-id.json | 7 +- dist/schemas/2.6.0/core/property-tag.json | 9 +- dist/schemas/2.6.0/core/property.json | 17 +- .../schemas/2.6.0/core/protocol-envelope.json | 8 +- .../core/publisher-property-selector.json | 23 +- .../2.6.0/core/push-notification-config.json | 10 +- .../2.6.0/core/reporting-capabilities.json | 38 +- dist/schemas/2.6.0/core/response.json | 8 +- dist/schemas/2.6.0/core/signal-filters.json | 2 +- dist/schemas/2.6.0/core/sub-asset.json | 18 +- dist/schemas/2.6.0/core/targeting.json | 4 +- .../schemas/2.6.0/core/tasks-get-request.json | 2 +- .../2.6.0/core/tasks-get-response.json | 8 +- .../2.6.0/core/tasks-list-request.json | 8 +- .../2.6.0/core/tasks-list-response.json | 12 +- .../2.6.0/creative/asset-types/index.json | 7 +- .../list-creative-formats-request.json | 2 +- .../list-creative-formats-response.json | 2 +- .../creative/preview-creative-request.json | 12 +- .../creative/preview-creative-response.json | 4 +- .../2.6.0/creative/preview-render.json | 43 +- dist/schemas/2.6.0/enums/adcp-domain.json | 5 +- dist/schemas/2.6.0/enums/auth-scheme.json | 5 +- .../2.6.0/enums/co-branding-requirement.json | 6 +- dist/schemas/2.6.0/enums/creative-action.json | 8 +- .../enums/creative-agent-capability.json | 7 +- dist/schemas/2.6.0/enums/creative-status.json | 9 +- dist/schemas/2.6.0/enums/daast-version.json | 5 +- dist/schemas/2.6.0/enums/delivery-type.json | 7 +- dist/schemas/2.6.0/enums/dimension-unit.json | 7 +- dist/schemas/2.6.0/enums/feed-format.json | 6 +- .../2.6.0/enums/format-id-parameter.json | 5 +- .../2.6.0/enums/frequency-cap-scope.json | 6 +- .../2.6.0/enums/history-entry-type.json | 5 +- dist/schemas/2.6.0/enums/http-method.json | 5 +- .../schemas/2.6.0/enums/identifier-types.json | 6 +- .../2.6.0/enums/javascript-module-type.json | 6 +- .../2.6.0/enums/landing-page-requirement.json | 6 +- dist/schemas/2.6.0/enums/markdown-flavor.json | 5 +- .../schemas/2.6.0/enums/media-buy-status.json | 9 +- .../2.6.0/enums/notification-type.json | 7 +- dist/schemas/2.6.0/enums/pacing.json | 8 +- .../2.6.0/enums/preview-output-format.json | 5 +- .../2.6.0/enums/reporting-frequency.json | 6 +- .../2.6.0/enums/signal-catalog-type.json | 6 +- dist/schemas/2.6.0/enums/sort-direction.json | 5 +- .../2.6.0/enums/standard-format-ids.json | 2 +- dist/schemas/2.6.0/enums/task-status.json | 6 +- .../schemas/2.6.0/enums/update-frequency.json | 7 +- dist/schemas/2.6.0/enums/url-asset-type.json | 6 +- dist/schemas/2.6.0/enums/validation-mode.json | 5 +- dist/schemas/2.6.0/enums/vast-version.json | 8 +- .../2.6.0/enums/webhook-response-type.json | 7 +- .../2.6.0/enums/webhook-security-method.json | 6 +- dist/schemas/2.6.0/index.json | 4 +- .../media-buy/build-creative-request.json | 2 +- .../media-buy/build-creative-response.json | 4 +- ...dia-buy-async-response-input-required.json | 2 +- ...te-media-buy-async-response-submitted.json | 3 +- ...eate-media-buy-async-response-working.json | 3 +- .../media-buy/create-media-buy-request.json | 15 +- .../media-buy/create-media-buy-response.json | 4 +- .../get-media-buy-delivery-request.json | 2 +- .../get-media-buy-delivery-response.json | 10 +- ...roducts-async-response-input-required.json | 3 +- ...get-products-async-response-submitted.json | 3 +- .../get-products-async-response-working.json | 3 +- .../2.6.0/media-buy/get-products-request.json | 2 +- .../media-buy/get-products-response.json | 2 +- .../list-authorized-properties-request.json | 2 +- .../list-authorized-properties-response.json | 2 +- .../list-creative-formats-request.json | 2 +- .../list-creative-formats-response.json | 2 +- .../media-buy/list-creatives-request.json | 6 +- .../media-buy/list-creatives-response.json | 18 +- .../2.6.0/media-buy/package-request.json | 2 +- .../provide-performance-feedback-request.json | 4 +- ...provide-performance-feedback-response.json | 4 +- ...eatives-async-response-input-required.json | 2 +- ...nc-creatives-async-response-submitted.json | 3 +- ...sync-creatives-async-response-working.json | 3 +- .../media-buy/sync-creatives-request.json | 9 +- .../media-buy/sync-creatives-response.json | 8 +- ...dia-buy-async-response-input-required.json | 3 +- ...te-media-buy-async-response-submitted.json | 3 +- ...date-media-buy-async-response-working.json | 3 +- .../media-buy/update-media-buy-request.json | 4 +- .../media-buy/update-media-buy-response.json | 4 +- .../2.6.0/pricing-options/cpc-option.json | 17 +- .../2.6.0/pricing-options/cpcv-option.json | 17 +- .../pricing-options/cpm-auction-option.json | 21 +- .../pricing-options/cpm-fixed-option.json | 17 +- .../2.6.0/pricing-options/cpp-option.json | 24 +- .../2.6.0/pricing-options/cpv-option.json | 30 +- .../pricing-options/flat-rate-option.json | 19 +- .../pricing-options/vcpm-auction-option.json | 21 +- .../pricing-options/vcpm-fixed-option.json | 17 +- .../2.6.0/protocols/adcp-extension.json | 13 +- .../signals/activate-signal-request.json | 2 +- .../signals/activate-signal-response.json | 4 +- .../2.6.0/signals/get-signals-request.json | 4 +- .../2.6.0/signals/get-signals-response.json | 6 +- static/schemas/source/index.json | 2 +- 166 files changed, 1736 insertions(+), 1024 deletions(-) diff --git a/dist/schemas/2.6.0/adagents.json b/dist/schemas/2.6.0/adagents.json index dd9ad29277..4fafdaa844 100644 --- a/dist/schemas/2.6.0/adagents.json +++ b/dist/schemas/2.6.0/adagents.json @@ -24,8 +24,10 @@ "description": "ISO 8601 timestamp indicating when this reference was last updated" } }, - "required": ["authoritative_location"], - "additionalProperties": false + "required": [ + "authoritative_location" + ], + "additionalProperties": true }, { "type": "object", @@ -36,211 +38,238 @@ "description": "JSON Schema identifier for this adagents.json file" }, "contact": { - "type": "object", - "description": "Contact information for the entity managing this adagents.json file (may be publisher or third-party operator)", - "properties": { - "name": { - "type": "string", - "description": "Name of the entity managing this file (e.g., 'Meta Advertising Operations', 'Clear Channel Digital')", - "minLength": 1, - "maxLength": 255 - }, - "email": { - "type": "string", - "format": "email", - "description": "Contact email for questions or issues with this authorization file", - "minLength": 1, - "maxLength": 255 - }, - "domain": { - "type": "string", - "description": "Primary domain of the entity managing this file", - "pattern": "^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$" - }, - "seller_id": { - "type": "string", - "description": "Seller ID from IAB Tech Lab sellers.json (if applicable)", - "minLength": 1, - "maxLength": 255 + "type": "object", + "description": "Contact information for the entity managing this adagents.json file (may be publisher or third-party operator)", + "properties": { + "name": { + "type": "string", + "description": "Name of the entity managing this file (e.g., 'Meta Advertising Operations', 'Clear Channel Digital')", + "minLength": 1, + "maxLength": 255 + }, + "email": { + "type": "string", + "format": "email", + "description": "Contact email for questions or issues with this authorization file", + "minLength": 1, + "maxLength": 255 + }, + "domain": { + "type": "string", + "description": "Primary domain of the entity managing this file", + "pattern": "^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$" + }, + "seller_id": { + "type": "string", + "description": "Seller ID from IAB Tech Lab sellers.json (if applicable)", + "minLength": 1, + "maxLength": 255 + }, + "tag_id": { + "type": "string", + "description": "TAG Certified Against Fraud ID for verification (if applicable)", + "minLength": 1, + "maxLength": 100 + } + }, + "required": [ + "name" + ], + "additionalProperties": true }, - "tag_id": { - "type": "string", - "description": "TAG Certified Against Fraud ID for verification (if applicable)", - "minLength": 1, - "maxLength": 100 - } - }, - "required": ["name"], - "additionalProperties": false - }, - "properties": { - "type": "array", - "description": "Array of all properties covered by this adagents.json file. Defines the canonical property list that authorized agents reference.", - "items": { - "$ref": "/schemas/2.6.0/core/property.json" - }, - "minItems": 1 - }, - "tags": { - "type": "object", - "description": "Metadata for each tag referenced by properties. Provides human-readable context for property tag values.", - "additionalProperties": { - "type": "object", "properties": { - "name": { - "type": "string", - "description": "Human-readable name for this tag" + "type": "array", + "description": "Array of all properties covered by this adagents.json file. Defines the canonical property list that authorized agents reference.", + "items": { + "$ref": "/schemas/2.6.0/core/property.json" }, - "description": { - "type": "string", - "description": "Description of what this tag represents" - } + "minItems": 1 }, - "required": ["name", "description"], - "additionalProperties": false - } - }, - "authorized_agents": { - "type": "array", - "description": "Array of sales agents authorized to sell inventory for properties in this file", - "items": { - "oneOf": [ - { + "tags": { + "type": "object", + "description": "Metadata for each tag referenced by properties. Provides human-readable context for property tag values.", + "additionalProperties": { "type": "object", "properties": { - "url": { + "name": { "type": "string", - "format": "uri", - "description": "The authorized agent's API endpoint URL" + "description": "Human-readable name for this tag" }, - "authorized_for": { + "description": { "type": "string", - "description": "Human-readable description of what this agent is authorized to sell", - "minLength": 1, - "maxLength": 500 - }, - "authorization_type": { - "type": "string", - "const": "property_ids", - "description": "Discriminator indicating authorization by specific property IDs" - }, - "property_ids": { - "type": "array", - "description": "Property IDs this agent is authorized for. Resolved against the top-level properties array in this file", - "items": { - "$ref": "/schemas/2.6.0/core/property-id.json" - }, - "minItems": 1 + "description": "Description of what this tag represents" } }, - "required": ["url", "authorized_for", "authorization_type", "property_ids"], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "url": { - "type": "string", - "format": "uri", - "description": "The authorized agent's API endpoint URL" - }, - "authorized_for": { - "type": "string", - "description": "Human-readable description of what this agent is authorized to sell", - "minLength": 1, - "maxLength": 500 - }, - "authorization_type": { - "type": "string", - "const": "property_tags", - "description": "Discriminator indicating authorization by property tags" - }, - "property_tags": { - "type": "array", - "description": "Tags identifying which properties this agent is authorized for. Resolved against the top-level properties array in this file using tag matching", - "items": { - "$ref": "/schemas/2.6.0/core/property-tag.json" + "required": [ + "name", + "description" + ], + "additionalProperties": true + } + }, + "authorized_agents": { + "type": "array", + "description": "Array of sales agents authorized to sell inventory for properties in this file", + "items": { + "oneOf": [ + { + "type": "object", + "properties": { + "url": { + "type": "string", + "format": "uri", + "description": "The authorized agent's API endpoint URL" + }, + "authorized_for": { + "type": "string", + "description": "Human-readable description of what this agent is authorized to sell", + "minLength": 1, + "maxLength": 500 + }, + "authorization_type": { + "type": "string", + "const": "property_ids", + "description": "Discriminator indicating authorization by specific property IDs" + }, + "property_ids": { + "type": "array", + "description": "Property IDs this agent is authorized for. Resolved against the top-level properties array in this file", + "items": { + "$ref": "/schemas/2.6.0/core/property-id.json" + }, + "minItems": 1 + } }, - "minItems": 1 - } - }, - "required": ["url", "authorized_for", "authorization_type", "property_tags"], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "url": { - "type": "string", - "format": "uri", - "description": "The authorized agent's API endpoint URL" - }, - "authorized_for": { - "type": "string", - "description": "Human-readable description of what this agent is authorized to sell", - "minLength": 1, - "maxLength": 500 + "required": [ + "url", + "authorized_for", + "authorization_type", + "property_ids" + ], + "additionalProperties": true }, - "authorization_type": { - "type": "string", - "const": "inline_properties", - "description": "Discriminator indicating authorization by inline property definitions" - }, - "properties": { - "type": "array", - "description": "Specific properties this agent is authorized for (alternative to property_ids/property_tags)", - "items": { - "$ref": "/schemas/2.6.0/core/property.json" + { + "type": "object", + "properties": { + "url": { + "type": "string", + "format": "uri", + "description": "The authorized agent's API endpoint URL" + }, + "authorized_for": { + "type": "string", + "description": "Human-readable description of what this agent is authorized to sell", + "minLength": 1, + "maxLength": 500 + }, + "authorization_type": { + "type": "string", + "const": "property_tags", + "description": "Discriminator indicating authorization by property tags" + }, + "property_tags": { + "type": "array", + "description": "Tags identifying which properties this agent is authorized for. Resolved against the top-level properties array in this file using tag matching", + "items": { + "$ref": "/schemas/2.6.0/core/property-tag.json" + }, + "minItems": 1 + } }, - "minItems": 1 - } - }, - "required": ["url", "authorized_for", "authorization_type", "properties"], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "url": { - "type": "string", - "format": "uri", - "description": "The authorized agent's API endpoint URL" + "required": [ + "url", + "authorized_for", + "authorization_type", + "property_tags" + ], + "additionalProperties": true }, - "authorized_for": { - "type": "string", - "description": "Human-readable description of what this agent is authorized to sell", - "minLength": 1, - "maxLength": 500 - }, - "authorization_type": { - "type": "string", - "const": "publisher_properties", - "description": "Discriminator indicating authorization for properties from other publisher domains" + { + "type": "object", + "properties": { + "url": { + "type": "string", + "format": "uri", + "description": "The authorized agent's API endpoint URL" + }, + "authorized_for": { + "type": "string", + "description": "Human-readable description of what this agent is authorized to sell", + "minLength": 1, + "maxLength": 500 + }, + "authorization_type": { + "type": "string", + "const": "inline_properties", + "description": "Discriminator indicating authorization by inline property definitions" + }, + "properties": { + "type": "array", + "description": "Specific properties this agent is authorized for (alternative to property_ids/property_tags)", + "items": { + "$ref": "/schemas/2.6.0/core/property.json" + }, + "minItems": 1 + } + }, + "required": [ + "url", + "authorized_for", + "authorization_type", + "properties" + ], + "additionalProperties": true }, - "publisher_properties": { - "type": "array", - "description": "Properties from other publisher domains this agent is authorized for. Each entry specifies a publisher domain and which of their properties this agent can sell", - "items": { - "$ref": "/schemas/2.6.0/core/publisher-property-selector.json" + { + "type": "object", + "properties": { + "url": { + "type": "string", + "format": "uri", + "description": "The authorized agent's API endpoint URL" + }, + "authorized_for": { + "type": "string", + "description": "Human-readable description of what this agent is authorized to sell", + "minLength": 1, + "maxLength": 500 + }, + "authorization_type": { + "type": "string", + "const": "publisher_properties", + "description": "Discriminator indicating authorization for properties from other publisher domains" + }, + "publisher_properties": { + "type": "array", + "description": "Properties from other publisher domains this agent is authorized for. Each entry specifies a publisher domain and which of their properties this agent can sell", + "items": { + "$ref": "/schemas/2.6.0/core/publisher-property-selector.json" + }, + "minItems": 1 + } }, - "minItems": 1 + "required": [ + "url", + "authorized_for", + "authorization_type", + "publisher_properties" + ], + "additionalProperties": true } - }, - "required": ["url", "authorized_for", "authorization_type", "publisher_properties"], - "additionalProperties": false - } - ] - }, - "minItems": 1 - }, + ] + }, + "minItems": 1 + }, "last_updated": { "type": "string", "format": "date-time", "description": "ISO 8601 timestamp indicating when this file was last updated" } }, - "required": ["authorized_agents"], - "additionalProperties": false + "required": [ + "authorized_agents" + ], + "additionalProperties": true } ], "examples": [ @@ -256,7 +285,10 @@ "property_type": "website", "name": "Example Site", "identifiers": [ - {"type": "domain", "value": "example.com"} + { + "type": "domain", + "value": "example.com" + } ], "publisher_domain": "example.com" } @@ -266,7 +298,9 @@ "url": "https://agent.example.com", "authorized_for": "Official sales agent", "authorization_type": "property_tags", - "property_tags": ["all"] + "property_tags": [ + "all" + ] } ], "tags": { @@ -291,30 +325,57 @@ "property_type": "mobile_app", "name": "Instagram", "identifiers": [ - {"type": "ios_bundle", "value": "com.burbn.instagram"}, - {"type": "android_package", "value": "com.instagram.android"} + { + "type": "ios_bundle", + "value": "com.burbn.instagram" + }, + { + "type": "android_package", + "value": "com.instagram.android" + } + ], + "tags": [ + "meta_network", + "social_media" ], - "tags": ["meta_network", "social_media"], "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"} + { + "type": "ios_bundle", + "value": "com.facebook.Facebook" + }, + { + "type": "android_package", + "value": "com.facebook.katana" + } + ], + "tags": [ + "meta_network", + "social_media" ], - "tags": ["meta_network", "social_media"], "publisher_domain": "facebook.com" }, { "property_type": "mobile_app", "name": "WhatsApp", "identifiers": [ - {"type": "ios_bundle", "value": "net.whatsapp.WhatsApp"}, - {"type": "android_package", "value": "com.whatsapp"} + { + "type": "ios_bundle", + "value": "net.whatsapp.WhatsApp" + }, + { + "type": "android_package", + "value": "com.whatsapp" + } + ], + "tags": [ + "meta_network", + "messaging" ], - "tags": ["meta_network", "messaging"], "publisher_domain": "whatsapp.com" } ], @@ -337,7 +398,9 @@ "url": "https://meta-ads.com", "authorized_for": "All Meta properties", "authorization_type": "property_tags", - "property_tags": ["meta_network"] + "property_tags": [ + "meta_network" + ] } ], "last_updated": "2025-01-10T15:30:00Z" @@ -352,9 +415,14 @@ "property_type": "website", "name": "Tumblr Corporate", "identifiers": [ - {"type": "domain", "value": "tumblr.com"} + { + "type": "domain", + "value": "tumblr.com" + } + ], + "tags": [ + "corporate" ], - "tags": ["corporate"], "publisher_domain": "tumblr.com" } ], @@ -369,7 +437,9 @@ "url": "https://tumblr-sales.com", "authorized_for": "Tumblr corporate properties only", "authorization_type": "property_tags", - "property_tags": ["corporate"] + "property_tags": [ + "corporate" + ] } ], "last_updated": "2025-01-10T16:00:00Z" @@ -390,7 +460,9 @@ { "publisher_domain": "cnn.com", "selection_type": "by_id", - "property_ids": ["cnn_ctv_app"] + "property_ids": [ + "cnn_ctv_app" + ] } ] }, @@ -402,12 +474,16 @@ { "publisher_domain": "cnn.com", "selection_type": "by_tag", - "property_tags": ["ctv"] + "property_tags": [ + "ctv" + ] }, { "publisher_domain": "espn.com", "selection_type": "by_tag", - "property_tags": ["ctv"] + "property_tags": [ + "ctv" + ] } ] } @@ -415,4 +491,4 @@ "last_updated": "2025-01-10T17:00:00Z" } ] -} \ No newline at end of file +} diff --git a/dist/schemas/2.6.0/bundled/media-buy/build-creative-request.json b/dist/schemas/2.6.0/bundled/media-buy/build-creative-request.json index 96138d0284..add3c1ba85 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/build-creative-request.json +++ b/dist/schemas/2.6.0/bundled/media-buy/build-creative-request.json @@ -49,7 +49,7 @@ "agent_url", "id" ], - "additionalProperties": false, + "additionalProperties": true, "dependencies": { "width": [ "height" @@ -103,7 +103,7 @@ "width", "height" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "Video Asset", @@ -145,7 +145,7 @@ "width", "height" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "Audio Asset", @@ -175,7 +175,7 @@ "required": [ "url" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "VAST Asset", @@ -247,7 +247,7 @@ "delivery_type", "url" ], - "additionalProperties": false + "additionalProperties": true }, { "type": "object", @@ -314,7 +314,7 @@ "delivery_type", "content" ], - "additionalProperties": false + "additionalProperties": true } ] }, @@ -335,7 +335,7 @@ "required": [ "content" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "URL Asset", @@ -365,7 +365,7 @@ "required": [ "url" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "HTML Asset", @@ -384,7 +384,7 @@ "required": [ "content" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "JavaScript Asset", @@ -409,7 +409,7 @@ "required": [ "content" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "Webhook Asset", @@ -496,7 +496,7 @@ "response_type", "security" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "CSS Asset", @@ -515,7 +515,7 @@ "required": [ "content" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "DAAST Asset", @@ -579,7 +579,7 @@ "delivery_type", "url" ], - "additionalProperties": false + "additionalProperties": true }, { "type": "object", @@ -638,7 +638,7 @@ "delivery_type", "content" ], - "additionalProperties": false + "additionalProperties": true } ] }, @@ -839,7 +839,7 @@ "asset_type", "url" ], - "additionalProperties": false + "additionalProperties": true } }, "product_catalog": { @@ -887,7 +887,7 @@ "required": [ "feed_url" ], - "additionalProperties": false + "additionalProperties": true }, "disclaimers": { "type": "array", @@ -961,7 +961,7 @@ "required": [ "name" ], - "additionalProperties": false, + "additionalProperties": true, "examples": [ { "description": "Example with both URL and name", @@ -1125,7 +1125,7 @@ "description": "Natural language query to select products from the brand manifest (e.g., 'all Kraft Heinz pasta sauces', 'organic products under $20')" } }, - "additionalProperties": false, + "additionalProperties": true, "examples": [ { "description": "Direct SKU selection for specific products from brand manifest", @@ -1189,7 +1189,7 @@ "required": [ "name" ], - "additionalProperties": false + "additionalProperties": true } }, "asset_selectors": { @@ -1231,13 +1231,13 @@ } } }, - "additionalProperties": false + "additionalProperties": true } }, "required": [ "brand_manifest" ], - "additionalProperties": false, + "additionalProperties": true, "examples": [ { "brand_manifest": { @@ -1265,7 +1265,7 @@ ] } }, - "additionalProperties": false + "additionalProperties": true }, "ext": { "title": "Extension Object", @@ -1278,7 +1278,7 @@ "format_id", "assets" ], - "additionalProperties": false + "additionalProperties": true }, "target_format_id": { "title": "Format ID", @@ -1315,7 +1315,7 @@ "agent_url", "id" ], - "additionalProperties": false, + "additionalProperties": true, "dependencies": { "width": [ "height" @@ -1341,9 +1341,9 @@ "required": [ "target_format_id" ], - "additionalProperties": false, + "additionalProperties": true, "_bundled": { - "generatedAt": "2026-01-05T18:19:47.402Z", - "note": "This is a bundled schema with all $ref resolved inline." + "generatedAt": "2026-01-07T19:56:54.823Z", + "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/build-creative-response.json b/dist/schemas/2.6.0/bundled/media-buy/build-creative-response.json index 5b0748d268..d3b8342b62 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/build-creative-response.json +++ b/dist/schemas/2.6.0/bundled/media-buy/build-creative-response.json @@ -50,7 +50,7 @@ "agent_url", "id" ], - "additionalProperties": false, + "additionalProperties": true, "dependencies": { "width": [ "height" @@ -104,7 +104,7 @@ "width", "height" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "Video Asset", @@ -146,7 +146,7 @@ "width", "height" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "Audio Asset", @@ -176,7 +176,7 @@ "required": [ "url" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "VAST Asset", @@ -248,7 +248,7 @@ "delivery_type", "url" ], - "additionalProperties": false + "additionalProperties": true }, { "type": "object", @@ -315,7 +315,7 @@ "delivery_type", "content" ], - "additionalProperties": false + "additionalProperties": true } ] }, @@ -336,7 +336,7 @@ "required": [ "content" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "URL Asset", @@ -366,7 +366,7 @@ "required": [ "url" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "HTML Asset", @@ -385,7 +385,7 @@ "required": [ "content" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "JavaScript Asset", @@ -410,7 +410,7 @@ "required": [ "content" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "Webhook Asset", @@ -497,7 +497,7 @@ "response_type", "security" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "CSS Asset", @@ -516,7 +516,7 @@ "required": [ "content" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "DAAST Asset", @@ -580,7 +580,7 @@ "delivery_type", "url" ], - "additionalProperties": false + "additionalProperties": true }, { "type": "object", @@ -639,7 +639,7 @@ "delivery_type", "content" ], - "additionalProperties": false + "additionalProperties": true } ] }, @@ -840,7 +840,7 @@ "asset_type", "url" ], - "additionalProperties": false + "additionalProperties": true } }, "product_catalog": { @@ -888,7 +888,7 @@ "required": [ "feed_url" ], - "additionalProperties": false + "additionalProperties": true }, "disclaimers": { "type": "array", @@ -962,7 +962,7 @@ "required": [ "name" ], - "additionalProperties": false, + "additionalProperties": true, "examples": [ { "description": "Example with both URL and name", @@ -1126,7 +1126,7 @@ "description": "Natural language query to select products from the brand manifest (e.g., 'all Kraft Heinz pasta sauces', 'organic products under $20')" } }, - "additionalProperties": false, + "additionalProperties": true, "examples": [ { "description": "Direct SKU selection for specific products from brand manifest", @@ -1190,7 +1190,7 @@ "required": [ "name" ], - "additionalProperties": false + "additionalProperties": true } }, "asset_selectors": { @@ -1232,13 +1232,13 @@ } } }, - "additionalProperties": false + "additionalProperties": true } }, "required": [ "brand_manifest" ], - "additionalProperties": false, + "additionalProperties": true, "examples": [ { "brand_manifest": { @@ -1266,7 +1266,7 @@ ] } }, - "additionalProperties": false + "additionalProperties": true }, "ext": { "title": "Extension Object", @@ -1279,7 +1279,7 @@ "format_id", "assets" ], - "additionalProperties": false + "additionalProperties": true }, "context": { "title": "Context Object", @@ -1297,7 +1297,7 @@ "required": [ "creative_manifest" ], - "additionalProperties": false, + "additionalProperties": true, "not": { "required": [ "errors" @@ -1339,14 +1339,16 @@ "minimum": 0 }, "details": { - "description": "Additional task-specific error details" + "type": "object", + "description": "Additional task-specific error details", + "additionalProperties": true } }, "required": [ "code", "message" ], - "additionalProperties": false + "additionalProperties": true }, "minItems": 1 }, @@ -1366,7 +1368,7 @@ "required": [ "errors" ], - "additionalProperties": false, + "additionalProperties": true, "not": { "required": [ "creative_manifest" @@ -1375,7 +1377,7 @@ } ], "_bundled": { - "generatedAt": "2026-01-05T18:19:47.404Z", - "note": "This is a bundled schema with all $ref resolved inline." + "generatedAt": "2026-01-07T19:56:54.825Z", + "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/create-media-buy-request.json b/dist/schemas/2.6.0/bundled/media-buy/create-media-buy-request.json index b48889e787..9b5f26e79c 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/create-media-buy-request.json +++ b/dist/schemas/2.6.0/bundled/media-buy/create-media-buy-request.json @@ -63,7 +63,7 @@ "agent_url", "id" ], - "additionalProperties": false, + "additionalProperties": true, "dependencies": { "width": [ "height" @@ -160,10 +160,10 @@ "required": [ "suppress_minutes" ], - "additionalProperties": false + "additionalProperties": true } }, - "additionalProperties": false + "additionalProperties": true }, "creative_ids": { "type": "array", @@ -223,7 +223,7 @@ "agent_url", "id" ], - "additionalProperties": false, + "additionalProperties": true, "dependencies": { "width": [ "height" @@ -273,7 +273,7 @@ "width", "height" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "Video Asset", @@ -315,7 +315,7 @@ "width", "height" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "Audio Asset", @@ -345,7 +345,7 @@ "required": [ "url" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "Text Asset", @@ -364,7 +364,7 @@ "required": [ "content" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "HTML Asset", @@ -383,7 +383,7 @@ "required": [ "content" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "CSS Asset", @@ -402,7 +402,7 @@ "required": [ "content" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "JavaScript Asset", @@ -427,7 +427,7 @@ "required": [ "content" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "VAST Asset", @@ -499,7 +499,7 @@ "delivery_type", "url" ], - "additionalProperties": false + "additionalProperties": true }, { "type": "object", @@ -566,7 +566,7 @@ "delivery_type", "content" ], - "additionalProperties": false + "additionalProperties": true } ] }, @@ -632,7 +632,7 @@ "delivery_type", "url" ], - "additionalProperties": false + "additionalProperties": true }, { "type": "object", @@ -691,7 +691,7 @@ "delivery_type", "content" ], - "additionalProperties": false + "additionalProperties": true } ] }, @@ -892,7 +892,7 @@ "asset_type", "url" ], - "additionalProperties": false + "additionalProperties": true } }, "product_catalog": { @@ -940,7 +940,7 @@ "required": [ "feed_url" ], - "additionalProperties": false + "additionalProperties": true }, "disclaimers": { "type": "array", @@ -1014,7 +1014,7 @@ "required": [ "name" ], - "additionalProperties": false, + "additionalProperties": true, "examples": [ { "description": "Example with both URL and name", @@ -1178,7 +1178,7 @@ "description": "Natural language query to select products from the brand manifest (e.g., 'all Kraft Heinz pasta sauces', 'organic products under $20')" } }, - "additionalProperties": false, + "additionalProperties": true, "examples": [ { "description": "Direct SKU selection for specific products from brand manifest", @@ -1242,7 +1242,7 @@ "required": [ "name" ], - "additionalProperties": false + "additionalProperties": true } }, "asset_selectors": { @@ -1284,13 +1284,13 @@ } } }, - "additionalProperties": false + "additionalProperties": true } }, "required": [ "brand_manifest" ], - "additionalProperties": false, + "additionalProperties": true, "examples": [ { "brand_manifest": { @@ -1343,12 +1343,12 @@ "required": [ "url" ], - "additionalProperties": false + "additionalProperties": true } ] } }, - "additionalProperties": false + "additionalProperties": true }, "inputs": { "type": "array", @@ -1375,7 +1375,7 @@ "required": [ "name" ], - "additionalProperties": false + "additionalProperties": true } }, "tags": { @@ -1410,7 +1410,7 @@ "format_id", "assets" ], - "additionalProperties": false + "additionalProperties": true }, "maxItems": 100 }, @@ -1427,7 +1427,7 @@ "budget", "pricing_option_id" ], - "additionalProperties": false + "additionalProperties": true } }, "brand_manifest": { @@ -1622,7 +1622,7 @@ "asset_type", "url" ], - "additionalProperties": false + "additionalProperties": true } }, "product_catalog": { @@ -1670,7 +1670,7 @@ "required": [ "feed_url" ], - "additionalProperties": false + "additionalProperties": true }, "disclaimers": { "type": "array", @@ -1744,7 +1744,7 @@ "required": [ "name" ], - "additionalProperties": false, + "additionalProperties": true, "examples": [ { "description": "Example with both URL and name", @@ -1985,7 +1985,7 @@ "authentication", "reporting_frequency" ], - "additionalProperties": false + "additionalProperties": true }, "context": { "title": "Context Object", @@ -2007,9 +2007,9 @@ "start_time", "end_time" ], - "additionalProperties": false, + "additionalProperties": true, "_bundled": { - "generatedAt": "2026-01-05T18:19:47.417Z", - "note": "This is a bundled schema with all $ref resolved inline." + "generatedAt": "2026-01-07T19:56:54.826Z", + "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/create-media-buy-response.json b/dist/schemas/2.6.0/bundled/media-buy/create-media-buy-response.json index 8e78ef504d..8d99b96e93 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/create-media-buy-response.json +++ b/dist/schemas/2.6.0/bundled/media-buy/create-media-buy-response.json @@ -133,10 +133,10 @@ "required": [ "suppress_minutes" ], - "additionalProperties": false + "additionalProperties": true } }, - "additionalProperties": false + "additionalProperties": true }, "creative_assignments": { "type": "array", @@ -168,7 +168,7 @@ "required": [ "creative_id" ], - "additionalProperties": false + "additionalProperties": true } }, "format_ids_to_provide": { @@ -209,7 +209,7 @@ "agent_url", "id" ], - "additionalProperties": false, + "additionalProperties": true, "dependencies": { "width": [ "height" @@ -235,7 +235,7 @@ "required": [ "package_id" ], - "additionalProperties": false + "additionalProperties": true } }, "context": { @@ -256,7 +256,7 @@ "buyer_ref", "packages" ], - "additionalProperties": false, + "additionalProperties": true, "not": { "required": [ "errors" @@ -298,14 +298,16 @@ "minimum": 0 }, "details": { - "description": "Additional task-specific error details" + "type": "object", + "description": "Additional task-specific error details", + "additionalProperties": true } }, "required": [ "code", "message" ], - "additionalProperties": false + "additionalProperties": true }, "minItems": 1 }, @@ -325,7 +327,7 @@ "required": [ "errors" ], - "additionalProperties": false, + "additionalProperties": true, "not": { "anyOf": [ { @@ -348,7 +350,7 @@ } ], "_bundled": { - "generatedAt": "2026-01-05T18:19:47.418Z", - "note": "This is a bundled schema with all $ref resolved inline." + "generatedAt": "2026-01-07T19:56:54.827Z", + "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/get-media-buy-delivery-request.json b/dist/schemas/2.6.0/bundled/media-buy/get-media-buy-delivery-request.json index 2b3bd94030..26de332bc0 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/get-media-buy-delivery-request.json +++ b/dist/schemas/2.6.0/bundled/media-buy/get-media-buy-delivery-request.json @@ -84,9 +84,9 @@ "additionalProperties": true } }, - "additionalProperties": false, + "additionalProperties": true, "_bundled": { - "generatedAt": "2026-01-05T18:19:47.418Z", - "note": "This is a bundled schema with all $ref resolved inline." + "generatedAt": "2026-01-07T19:56:54.827Z", + "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/get-media-buy-delivery-response.json b/dist/schemas/2.6.0/bundled/media-buy/get-media-buy-delivery-response.json index 5c2b87edaa..e0053adb76 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/get-media-buy-delivery-response.json +++ b/dist/schemas/2.6.0/bundled/media-buy/get-media-buy-delivery-response.json @@ -53,7 +53,7 @@ "start", "end" ], - "additionalProperties": false + "additionalProperties": true }, "currency": { "type": "string", @@ -95,7 +95,7 @@ "spend", "media_buy_count" ], - "additionalProperties": false + "additionalProperties": true }, "media_buy_deliveries": { "type": "array", @@ -317,11 +317,11 @@ "venue_id", "impressions" ], - "additionalProperties": false + "additionalProperties": true } } }, - "additionalProperties": false + "additionalProperties": true } }, "additionalProperties": true @@ -507,11 +507,11 @@ "venue_id", "impressions" ], - "additionalProperties": false + "additionalProperties": true } } }, - "additionalProperties": false + "additionalProperties": true } }, "additionalProperties": true @@ -619,7 +619,7 @@ "impressions", "spend" ], - "additionalProperties": false + "additionalProperties": true } } }, @@ -629,7 +629,7 @@ "totals", "by_package" ], - "additionalProperties": false + "additionalProperties": true } }, "errors": { @@ -662,14 +662,16 @@ "minimum": 0 }, "details": { - "description": "Additional task-specific error details" + "type": "object", + "description": "Additional task-specific error details", + "additionalProperties": true } }, "required": [ "code", "message" ], - "additionalProperties": false + "additionalProperties": true } }, "context": { @@ -690,9 +692,9 @@ "currency", "media_buy_deliveries" ], - "additionalProperties": false, + "additionalProperties": true, "_bundled": { - "generatedAt": "2026-01-05T18:19:47.419Z", - "note": "This is a bundled schema with all $ref resolved inline." + "generatedAt": "2026-01-07T19:56:54.828Z", + "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/get-products-request.json b/dist/schemas/2.6.0/bundled/media-buy/get-products-request.json index d47e750e82..63d7d0ab1f 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/get-products-request.json +++ b/dist/schemas/2.6.0/bundled/media-buy/get-products-request.json @@ -201,7 +201,7 @@ "asset_type", "url" ], - "additionalProperties": false + "additionalProperties": true } }, "product_catalog": { @@ -249,7 +249,7 @@ "required": [ "feed_url" ], - "additionalProperties": false + "additionalProperties": true }, "disclaimers": { "type": "array", @@ -323,7 +323,7 @@ "required": [ "name" ], - "additionalProperties": false, + "additionalProperties": true, "examples": [ { "description": "Example with both URL and name", @@ -537,7 +537,7 @@ "agent_url", "id" ], - "additionalProperties": false, + "additionalProperties": true, "dependencies": { "width": [ "height" @@ -602,7 +602,7 @@ ] } ], - "additionalProperties": false + "additionalProperties": true }, "countries": { "type": "array", @@ -633,7 +633,7 @@ } } }, - "additionalProperties": false + "additionalProperties": true }, "context": { "title": "Context Object", @@ -649,9 +649,9 @@ } }, "required": [], - "additionalProperties": false, + "additionalProperties": true, "_bundled": { - "generatedAt": "2026-01-05T18:19:47.420Z", - "note": "This is a bundled schema with all $ref resolved inline." + "generatedAt": "2026-01-07T19:56:54.829Z", + "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/get-products-response.json b/dist/schemas/2.6.0/bundled/media-buy/get-products-response.json index 69d49af26d..b0599f53d8 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/get-products-response.json +++ b/dist/schemas/2.6.0/bundled/media-buy/get-products-response.json @@ -54,7 +54,7 @@ "publisher_domain", "selection_type" ], - "additionalProperties": false + "additionalProperties": true }, { "type": "object", @@ -93,7 +93,7 @@ "selection_type", "property_ids" ], - "additionalProperties": false + "additionalProperties": true }, { "type": "object", @@ -134,7 +134,7 @@ "selection_type", "property_tags" ], - "additionalProperties": false + "additionalProperties": true } ] }, @@ -178,7 +178,7 @@ "agent_url", "id" ], - "additionalProperties": false, + "additionalProperties": true, "dependencies": { "width": [ "height" @@ -247,7 +247,7 @@ "agent_url", "id" ], - "additionalProperties": false, + "additionalProperties": true, "dependencies": { "width": [ "height" @@ -264,7 +264,7 @@ "placement_id", "name" ], - "additionalProperties": false + "additionalProperties": true }, "minItems": 1 }, @@ -336,7 +336,7 @@ "currency", "is_fixed" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "CPM Auction Pricing Option", @@ -415,7 +415,7 @@ "currency", "is_fixed" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "vCPM Fixed Rate Pricing Option", @@ -465,7 +465,7 @@ "currency", "is_fixed" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "vCPM Auction Pricing Option", @@ -544,7 +544,7 @@ "price_guidance", "is_fixed" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "CPC Pricing Option", @@ -594,7 +594,7 @@ "currency", "is_fixed" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "CPCV Pricing Option", @@ -644,7 +644,7 @@ "currency", "is_fixed" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "CPV Pricing Option", @@ -706,7 +706,7 @@ "required": [ "duration_seconds" ], - "additionalProperties": false + "additionalProperties": true } ] } @@ -714,7 +714,7 @@ "required": [ "view_threshold" ], - "additionalProperties": false + "additionalProperties": true }, "min_spend_per_package": { "type": "number", @@ -730,7 +730,7 @@ "is_fixed", "parameters" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "CPP Pricing Option", @@ -785,7 +785,7 @@ "required": [ "demographic" ], - "additionalProperties": false + "additionalProperties": true }, "min_spend_per_package": { "type": "number", @@ -801,7 +801,7 @@ "is_fixed", "parameters" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "Flat Rate Pricing Option", @@ -877,7 +877,7 @@ "description": "Specific daypart for time-based pricing (e.g., 'morning_commute', 'evening_prime', 'overnight')" } }, - "additionalProperties": false + "additionalProperties": true }, "min_spend_per_package": { "type": "number", @@ -892,7 +892,7 @@ "is_fixed", "rate" ], - "additionalProperties": false + "additionalProperties": true } ] }, @@ -947,7 +947,7 @@ "attribution", "reporting" ], - "additionalProperties": false + "additionalProperties": true }, "delivery_measurement": { "type": "object", @@ -1053,7 +1053,7 @@ "supports_webhooks", "available_metrics" ], - "additionalProperties": false + "additionalProperties": true }, "creative_policy": { "title": "Creative Policy", @@ -1090,7 +1090,7 @@ "landing_page", "templates_available" ], - "additionalProperties": false + "additionalProperties": true }, "is_custom": { "type": "boolean", @@ -1144,7 +1144,7 @@ "agent_url", "id" ], - "additionalProperties": false, + "additionalProperties": true, "dependencies": { "width": [ "height" @@ -1164,7 +1164,7 @@ "format_id", "manifest" ], - "additionalProperties": false + "additionalProperties": true }, "product_card_detailed": { "type": "object", @@ -1205,7 +1205,7 @@ "agent_url", "id" ], - "additionalProperties": false, + "additionalProperties": true, "dependencies": { "width": [ "height" @@ -1225,7 +1225,7 @@ "format_id", "manifest" ], - "additionalProperties": false + "additionalProperties": true }, "ext": { "title": "Extension Object", @@ -1244,7 +1244,7 @@ "delivery_measurement", "pricing_options" ], - "additionalProperties": false + "additionalProperties": true } }, "errors": { @@ -1277,14 +1277,16 @@ "minimum": 0 }, "details": { - "description": "Additional task-specific error details" + "type": "object", + "description": "Additional task-specific error details", + "additionalProperties": true } }, "required": [ "code", "message" ], - "additionalProperties": false + "additionalProperties": true } }, "context": { @@ -1303,9 +1305,9 @@ "required": [ "products" ], - "additionalProperties": false, + "additionalProperties": true, "_bundled": { - "generatedAt": "2026-01-05T18:19:47.422Z", - "note": "This is a bundled schema with all $ref resolved inline." + "generatedAt": "2026-01-07T19:56:54.830Z", + "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/list-authorized-properties-request.json b/dist/schemas/2.6.0/bundled/media-buy/list-authorized-properties-request.json index 27c3a5d01b..7e4e17f7cf 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/list-authorized-properties-request.json +++ b/dist/schemas/2.6.0/bundled/media-buy/list-authorized-properties-request.json @@ -28,9 +28,9 @@ "additionalProperties": true } }, - "additionalProperties": false, + "additionalProperties": true, "_bundled": { - "generatedAt": "2026-01-05T18:19:47.423Z", - "note": "This is a bundled schema with all $ref resolved inline." + "generatedAt": "2026-01-07T19:56:54.830Z", + "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/list-authorized-properties-response.json b/dist/schemas/2.6.0/bundled/media-buy/list-authorized-properties-response.json index 91f7fbaee1..6ae624ec4f 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/list-authorized-properties-response.json +++ b/dist/schemas/2.6.0/bundled/media-buy/list-authorized-properties-response.json @@ -92,14 +92,16 @@ "minimum": 0 }, "details": { - "description": "Additional task-specific error details" + "type": "object", + "description": "Additional task-specific error details", + "additionalProperties": true } }, "required": [ "code", "message" ], - "additionalProperties": false + "additionalProperties": true } }, "context": { @@ -118,9 +120,9 @@ "required": [ "publisher_domains" ], - "additionalProperties": false, + "additionalProperties": true, "_bundled": { - "generatedAt": "2026-01-05T18:19:47.423Z", - "note": "This is a bundled schema with all $ref resolved inline." + "generatedAt": "2026-01-07T19:56:54.831Z", + "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/list-creative-formats-request.json b/dist/schemas/2.6.0/bundled/media-buy/list-creative-formats-request.json index d414941c5c..d02fc863f7 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/list-creative-formats-request.json +++ b/dist/schemas/2.6.0/bundled/media-buy/list-creative-formats-request.json @@ -43,7 +43,7 @@ "agent_url", "id" ], - "additionalProperties": false, + "additionalProperties": true, "dependencies": { "width": [ "height" @@ -129,9 +129,9 @@ "additionalProperties": true } }, - "additionalProperties": false, + "additionalProperties": true, "_bundled": { - "generatedAt": "2026-01-05T18:19:47.423Z", - "note": "This is a bundled schema with all $ref resolved inline." + "generatedAt": "2026-01-07T19:56:54.831Z", + "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/list-creative-formats-response.json b/dist/schemas/2.6.0/bundled/media-buy/list-creative-formats-response.json index e326584e67..ed691f6fa6 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/list-creative-formats-response.json +++ b/dist/schemas/2.6.0/bundled/media-buy/list-creative-formats-response.json @@ -48,7 +48,7 @@ "agent_url", "id" ], - "additionalProperties": false, + "additionalProperties": true, "dependencies": { "width": [ "height" @@ -554,7 +554,7 @@ "agent_url", "id" ], - "additionalProperties": false, + "additionalProperties": true, "dependencies": { "width": [ "height" @@ -604,7 +604,7 @@ "agent_url", "id" ], - "additionalProperties": false, + "additionalProperties": true, "dependencies": { "width": [ "height" @@ -624,7 +624,7 @@ "format_id", "manifest" ], - "additionalProperties": false + "additionalProperties": true }, "format_card_detailed": { "type": "object", @@ -665,7 +665,7 @@ "agent_url", "id" ], - "additionalProperties": false, + "additionalProperties": true, "dependencies": { "width": [ "height" @@ -685,7 +685,7 @@ "format_id", "manifest" ], - "additionalProperties": false + "additionalProperties": true } }, "required": [ @@ -693,7 +693,7 @@ "name", "type" ], - "additionalProperties": false + "additionalProperties": true } }, "creative_agents": { @@ -762,14 +762,16 @@ "minimum": 0 }, "details": { - "description": "Additional task-specific error details" + "type": "object", + "description": "Additional task-specific error details", + "additionalProperties": true } }, "required": [ "code", "message" ], - "additionalProperties": false + "additionalProperties": true } }, "context": { @@ -788,9 +790,9 @@ "required": [ "formats" ], - "additionalProperties": false, + "additionalProperties": true, "_bundled": { - "generatedAt": "2026-01-05T18:19:47.426Z", - "note": "This is a bundled schema with all $ref resolved inline." + "generatedAt": "2026-01-07T19:56:54.832Z", + "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/list-creatives-request.json b/dist/schemas/2.6.0/bundled/media-buy/list-creatives-request.json index 0263af51d4..319341183d 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/list-creatives-request.json +++ b/dist/schemas/2.6.0/bundled/media-buy/list-creatives-request.json @@ -139,7 +139,7 @@ "description": "Filter creatives that have performance data when true" } }, - "additionalProperties": false + "additionalProperties": true }, "sort": { "type": "object", @@ -170,7 +170,7 @@ "default": "desc" } }, - "additionalProperties": false + "additionalProperties": true }, "pagination": { "type": "object", @@ -190,7 +190,7 @@ "description": "Number of creatives to skip" } }, - "additionalProperties": false + "additionalProperties": true }, "include_assignments": { "type": "boolean", @@ -239,7 +239,7 @@ "additionalProperties": true } }, - "additionalProperties": false, + "additionalProperties": true, "examples": [ { "description": "List all approved video creatives", @@ -288,7 +288,7 @@ } ], "_bundled": { - "generatedAt": "2026-01-05T18:19:47.426Z", - "note": "This is a bundled schema with all $ref resolved inline." + "generatedAt": "2026-01-07T19:56:54.834Z", + "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/list-creatives-response.json b/dist/schemas/2.6.0/bundled/media-buy/list-creatives-response.json index 2730ab2038..ab7c867de7 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/list-creatives-response.json +++ b/dist/schemas/2.6.0/bundled/media-buy/list-creatives-response.json @@ -49,7 +49,7 @@ "total_matching", "returned" ], - "additionalProperties": false + "additionalProperties": true }, "pagination": { "type": "object", @@ -85,7 +85,7 @@ "offset", "has_more" ], - "additionalProperties": false + "additionalProperties": true }, "creatives": { "type": "array", @@ -136,7 +136,7 @@ "agent_url", "id" ], - "additionalProperties": false, + "additionalProperties": true, "dependencies": { "width": [ "height" @@ -213,7 +213,7 @@ "width", "height" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "Video Asset", @@ -255,7 +255,7 @@ "width", "height" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "Audio Asset", @@ -285,7 +285,7 @@ "required": [ "url" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "Text Asset", @@ -304,7 +304,7 @@ "required": [ "content" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "HTML Asset", @@ -323,7 +323,7 @@ "required": [ "content" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "CSS Asset", @@ -342,7 +342,7 @@ "required": [ "content" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "JavaScript Asset", @@ -367,7 +367,7 @@ "required": [ "content" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "VAST Asset", @@ -439,7 +439,7 @@ "delivery_type", "url" ], - "additionalProperties": false + "additionalProperties": true }, { "type": "object", @@ -506,7 +506,7 @@ "delivery_type", "content" ], - "additionalProperties": false + "additionalProperties": true } ] }, @@ -572,7 +572,7 @@ "delivery_type", "url" ], - "additionalProperties": false + "additionalProperties": true }, { "type": "object", @@ -631,7 +631,7 @@ "delivery_type", "content" ], - "additionalProperties": false + "additionalProperties": true } ] }, @@ -832,7 +832,7 @@ "asset_type", "url" ], - "additionalProperties": false + "additionalProperties": true } }, "product_catalog": { @@ -880,7 +880,7 @@ "required": [ "feed_url" ], - "additionalProperties": false + "additionalProperties": true }, "disclaimers": { "type": "array", @@ -954,7 +954,7 @@ "required": [ "name" ], - "additionalProperties": false, + "additionalProperties": true, "examples": [ { "description": "Example with both URL and name", @@ -1118,7 +1118,7 @@ "description": "Natural language query to select products from the brand manifest (e.g., 'all Kraft Heinz pasta sauces', 'organic products under $20')" } }, - "additionalProperties": false, + "additionalProperties": true, "examples": [ { "description": "Direct SKU selection for specific products from brand manifest", @@ -1182,7 +1182,7 @@ "required": [ "name" ], - "additionalProperties": false + "additionalProperties": true } }, "asset_selectors": { @@ -1224,13 +1224,13 @@ } } }, - "additionalProperties": false + "additionalProperties": true } }, "required": [ "brand_manifest" ], - "additionalProperties": false, + "additionalProperties": true, "examples": [ { "brand_manifest": { @@ -1283,7 +1283,7 @@ "required": [ "url" ], - "additionalProperties": false + "additionalProperties": true } ] } @@ -1339,14 +1339,14 @@ "assigned_date", "status" ], - "additionalProperties": false + "additionalProperties": true } } }, "required": [ "assignment_count" ], - "additionalProperties": false + "additionalProperties": true }, "performance": { "type": "object", @@ -1389,7 +1389,7 @@ "required": [ "last_updated" ], - "additionalProperties": false + "additionalProperties": true }, "sub_assets": { "type": "array", @@ -1426,7 +1426,7 @@ "asset_id", "content_uri" ], - "additionalProperties": false + "additionalProperties": true }, { "type": "object", @@ -1467,7 +1467,7 @@ "asset_id", "content" ], - "additionalProperties": false + "additionalProperties": true } ] } @@ -1481,7 +1481,7 @@ "created_date", "updated_date" ], - "additionalProperties": false + "additionalProperties": true } }, "format_summary": { @@ -1494,7 +1494,7 @@ "minimum": 0 } }, - "additionalProperties": false + "additionalProperties": true }, "status_summary": { "type": "object", @@ -1521,7 +1521,7 @@ "minimum": 0 } }, - "additionalProperties": false + "additionalProperties": true }, "context": { "title": "Context Object", @@ -1541,7 +1541,7 @@ "pagination", "creatives" ], - "additionalProperties": false, + "additionalProperties": true, "examples": [ { "description": "Successful library query with results", @@ -1648,7 +1648,7 @@ } ], "_bundled": { - "generatedAt": "2026-01-05T18:19:47.429Z", - "note": "This is a bundled schema with all $ref resolved inline." + "generatedAt": "2026-01-07T19:56:54.835Z", + "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/package-request.json b/dist/schemas/2.6.0/bundled/media-buy/package-request.json index 5b67b17850..7bc4ce1b75 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/package-request.json +++ b/dist/schemas/2.6.0/bundled/media-buy/package-request.json @@ -51,7 +51,7 @@ "agent_url", "id" ], - "additionalProperties": false, + "additionalProperties": true, "dependencies": { "width": [ "height" @@ -148,10 +148,10 @@ "required": [ "suppress_minutes" ], - "additionalProperties": false + "additionalProperties": true } }, - "additionalProperties": false + "additionalProperties": true }, "creative_ids": { "type": "array", @@ -211,7 +211,7 @@ "agent_url", "id" ], - "additionalProperties": false, + "additionalProperties": true, "dependencies": { "width": [ "height" @@ -261,7 +261,7 @@ "width", "height" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "Video Asset", @@ -303,7 +303,7 @@ "width", "height" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "Audio Asset", @@ -333,7 +333,7 @@ "required": [ "url" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "Text Asset", @@ -352,7 +352,7 @@ "required": [ "content" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "HTML Asset", @@ -371,7 +371,7 @@ "required": [ "content" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "CSS Asset", @@ -390,7 +390,7 @@ "required": [ "content" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "JavaScript Asset", @@ -415,7 +415,7 @@ "required": [ "content" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "VAST Asset", @@ -487,7 +487,7 @@ "delivery_type", "url" ], - "additionalProperties": false + "additionalProperties": true }, { "type": "object", @@ -554,7 +554,7 @@ "delivery_type", "content" ], - "additionalProperties": false + "additionalProperties": true } ] }, @@ -620,7 +620,7 @@ "delivery_type", "url" ], - "additionalProperties": false + "additionalProperties": true }, { "type": "object", @@ -679,7 +679,7 @@ "delivery_type", "content" ], - "additionalProperties": false + "additionalProperties": true } ] }, @@ -880,7 +880,7 @@ "asset_type", "url" ], - "additionalProperties": false + "additionalProperties": true } }, "product_catalog": { @@ -928,7 +928,7 @@ "required": [ "feed_url" ], - "additionalProperties": false + "additionalProperties": true }, "disclaimers": { "type": "array", @@ -1002,7 +1002,7 @@ "required": [ "name" ], - "additionalProperties": false, + "additionalProperties": true, "examples": [ { "description": "Example with both URL and name", @@ -1166,7 +1166,7 @@ "description": "Natural language query to select products from the brand manifest (e.g., 'all Kraft Heinz pasta sauces', 'organic products under $20')" } }, - "additionalProperties": false, + "additionalProperties": true, "examples": [ { "description": "Direct SKU selection for specific products from brand manifest", @@ -1230,7 +1230,7 @@ "required": [ "name" ], - "additionalProperties": false + "additionalProperties": true } }, "asset_selectors": { @@ -1272,13 +1272,13 @@ } } }, - "additionalProperties": false + "additionalProperties": true } }, "required": [ "brand_manifest" ], - "additionalProperties": false, + "additionalProperties": true, "examples": [ { "brand_manifest": { @@ -1331,12 +1331,12 @@ "required": [ "url" ], - "additionalProperties": false + "additionalProperties": true } ] } }, - "additionalProperties": false + "additionalProperties": true }, "inputs": { "type": "array", @@ -1363,7 +1363,7 @@ "required": [ "name" ], - "additionalProperties": false + "additionalProperties": true } }, "tags": { @@ -1398,7 +1398,7 @@ "format_id", "assets" ], - "additionalProperties": false + "additionalProperties": true }, "maxItems": 100 }, @@ -1415,9 +1415,9 @@ "budget", "pricing_option_id" ], - "additionalProperties": false, + "additionalProperties": true, "_bundled": { - "generatedAt": "2026-01-05T18:19:47.434Z", - "note": "This is a bundled schema with all $ref resolved inline." + "generatedAt": "2026-01-07T19:56:54.836Z", + "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/provide-performance-feedback-request.json b/dist/schemas/2.6.0/bundled/media-buy/provide-performance-feedback-request.json index f69755a28f..6a8d687c7f 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/provide-performance-feedback-request.json +++ b/dist/schemas/2.6.0/bundled/media-buy/provide-performance-feedback-request.json @@ -34,7 +34,7 @@ "start", "end" ], - "additionalProperties": false + "additionalProperties": true }, "performance_index": { "type": "number", @@ -108,9 +108,9 @@ ] } ], - "additionalProperties": false, + "additionalProperties": true, "_bundled": { - "generatedAt": "2026-01-05T18:19:47.435Z", - "note": "This is a bundled schema with all $ref resolved inline." + "generatedAt": "2026-01-07T19:56:54.837Z", + "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/provide-performance-feedback-response.json b/dist/schemas/2.6.0/bundled/media-buy/provide-performance-feedback-response.json index 638ca9efd4..6b4878652f 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/provide-performance-feedback-response.json +++ b/dist/schemas/2.6.0/bundled/media-buy/provide-performance-feedback-response.json @@ -31,7 +31,7 @@ "required": [ "success" ], - "additionalProperties": false, + "additionalProperties": true, "not": { "required": [ "errors" @@ -73,14 +73,16 @@ "minimum": 0 }, "details": { - "description": "Additional task-specific error details" + "type": "object", + "description": "Additional task-specific error details", + "additionalProperties": true } }, "required": [ "code", "message" ], - "additionalProperties": false + "additionalProperties": true }, "minItems": 1 }, @@ -100,7 +102,7 @@ "required": [ "errors" ], - "additionalProperties": false, + "additionalProperties": true, "not": { "required": [ "success" @@ -109,7 +111,7 @@ } ], "_bundled": { - "generatedAt": "2026-01-05T18:19:47.435Z", - "note": "This is a bundled schema with all $ref resolved inline." + "generatedAt": "2026-01-07T19:56:54.837Z", + "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/sync-creatives-request.json b/dist/schemas/2.6.0/bundled/media-buy/sync-creatives-request.json index f636e64908..0b56121358 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/sync-creatives-request.json +++ b/dist/schemas/2.6.0/bundled/media-buy/sync-creatives-request.json @@ -56,7 +56,7 @@ "agent_url", "id" ], - "additionalProperties": false, + "additionalProperties": true, "dependencies": { "width": [ "height" @@ -106,7 +106,7 @@ "width", "height" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "Video Asset", @@ -148,7 +148,7 @@ "width", "height" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "Audio Asset", @@ -178,7 +178,7 @@ "required": [ "url" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "Text Asset", @@ -197,7 +197,7 @@ "required": [ "content" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "HTML Asset", @@ -216,7 +216,7 @@ "required": [ "content" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "CSS Asset", @@ -235,7 +235,7 @@ "required": [ "content" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "JavaScript Asset", @@ -260,7 +260,7 @@ "required": [ "content" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "VAST Asset", @@ -332,7 +332,7 @@ "delivery_type", "url" ], - "additionalProperties": false + "additionalProperties": true }, { "type": "object", @@ -399,7 +399,7 @@ "delivery_type", "content" ], - "additionalProperties": false + "additionalProperties": true } ] }, @@ -465,7 +465,7 @@ "delivery_type", "url" ], - "additionalProperties": false + "additionalProperties": true }, { "type": "object", @@ -524,7 +524,7 @@ "delivery_type", "content" ], - "additionalProperties": false + "additionalProperties": true } ] }, @@ -725,7 +725,7 @@ "asset_type", "url" ], - "additionalProperties": false + "additionalProperties": true } }, "product_catalog": { @@ -773,7 +773,7 @@ "required": [ "feed_url" ], - "additionalProperties": false + "additionalProperties": true }, "disclaimers": { "type": "array", @@ -847,7 +847,7 @@ "required": [ "name" ], - "additionalProperties": false, + "additionalProperties": true, "examples": [ { "description": "Example with both URL and name", @@ -1011,7 +1011,7 @@ "description": "Natural language query to select products from the brand manifest (e.g., 'all Kraft Heinz pasta sauces', 'organic products under $20')" } }, - "additionalProperties": false, + "additionalProperties": true, "examples": [ { "description": "Direct SKU selection for specific products from brand manifest", @@ -1075,7 +1075,7 @@ "required": [ "name" ], - "additionalProperties": false + "additionalProperties": true } }, "asset_selectors": { @@ -1117,13 +1117,13 @@ } } }, - "additionalProperties": false + "additionalProperties": true } }, "required": [ "brand_manifest" ], - "additionalProperties": false, + "additionalProperties": true, "examples": [ { "brand_manifest": { @@ -1176,12 +1176,12 @@ "required": [ "url" ], - "additionalProperties": false + "additionalProperties": true } ] } }, - "additionalProperties": false + "additionalProperties": true }, "inputs": { "type": "array", @@ -1208,7 +1208,7 @@ "required": [ "name" ], - "additionalProperties": false + "additionalProperties": true } }, "tags": { @@ -1243,7 +1243,7 @@ "format_id", "assets" ], - "additionalProperties": false + "additionalProperties": true }, "maxItems": 100 }, @@ -1267,7 +1267,7 @@ } } }, - "additionalProperties": false + "additionalProperties": true }, "delete_missing": { "type": "boolean", @@ -1357,7 +1357,7 @@ "required": [ "creatives" ], - "additionalProperties": false, + "additionalProperties": true, "examples": [ { "description": "Full sync with hosted video creative", @@ -1469,7 +1469,7 @@ } ], "_bundled": { - "generatedAt": "2026-01-05T18:19:47.436Z", - "note": "This is a bundled schema with all $ref resolved inline." + "generatedAt": "2026-01-07T19:56:54.839Z", + "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/sync-creatives-response.json b/dist/schemas/2.6.0/bundled/media-buy/sync-creatives-response.json index f519c1ac77..cab162ded4 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/sync-creatives-response.json +++ b/dist/schemas/2.6.0/bundled/media-buy/sync-creatives-response.json @@ -87,14 +87,14 @@ "description": "Error message for this package assignment" } }, - "additionalProperties": false + "additionalProperties": true } }, "required": [ "creative_id", "action" ], - "additionalProperties": false + "additionalProperties": true } }, "context": { @@ -113,7 +113,7 @@ "required": [ "creatives" ], - "additionalProperties": false, + "additionalProperties": true, "not": { "required": [ "errors" @@ -155,14 +155,16 @@ "minimum": 0 }, "details": { - "description": "Additional task-specific error details" + "type": "object", + "description": "Additional task-specific error details", + "additionalProperties": true } }, "required": [ "code", "message" ], - "additionalProperties": false + "additionalProperties": true }, "minItems": 1 }, @@ -182,7 +184,7 @@ "required": [ "errors" ], - "additionalProperties": false, + "additionalProperties": true, "not": { "anyOf": [ { @@ -200,7 +202,7 @@ } ], "_bundled": { - "generatedAt": "2026-01-05T18:19:47.437Z", - "note": "This is a bundled schema with all $ref resolved inline." + "generatedAt": "2026-01-07T19:56:54.839Z", + "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/update-media-buy-request.json b/dist/schemas/2.6.0/bundled/media-buy/update-media-buy-request.json index a0d3994d9d..c8d8fa805e 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/update-media-buy-request.json +++ b/dist/schemas/2.6.0/bundled/media-buy/update-media-buy-request.json @@ -137,10 +137,10 @@ "required": [ "suppress_minutes" ], - "additionalProperties": false + "additionalProperties": true } }, - "additionalProperties": false + "additionalProperties": true }, "creative_ids": { "type": "array", @@ -200,7 +200,7 @@ "agent_url", "id" ], - "additionalProperties": false, + "additionalProperties": true, "dependencies": { "width": [ "height" @@ -250,7 +250,7 @@ "width", "height" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "Video Asset", @@ -292,7 +292,7 @@ "width", "height" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "Audio Asset", @@ -322,7 +322,7 @@ "required": [ "url" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "Text Asset", @@ -341,7 +341,7 @@ "required": [ "content" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "HTML Asset", @@ -360,7 +360,7 @@ "required": [ "content" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "CSS Asset", @@ -379,7 +379,7 @@ "required": [ "content" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "JavaScript Asset", @@ -404,7 +404,7 @@ "required": [ "content" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "VAST Asset", @@ -476,7 +476,7 @@ "delivery_type", "url" ], - "additionalProperties": false + "additionalProperties": true }, { "type": "object", @@ -543,7 +543,7 @@ "delivery_type", "content" ], - "additionalProperties": false + "additionalProperties": true } ] }, @@ -609,7 +609,7 @@ "delivery_type", "url" ], - "additionalProperties": false + "additionalProperties": true }, { "type": "object", @@ -668,7 +668,7 @@ "delivery_type", "content" ], - "additionalProperties": false + "additionalProperties": true } ] }, @@ -869,7 +869,7 @@ "asset_type", "url" ], - "additionalProperties": false + "additionalProperties": true } }, "product_catalog": { @@ -917,7 +917,7 @@ "required": [ "feed_url" ], - "additionalProperties": false + "additionalProperties": true }, "disclaimers": { "type": "array", @@ -991,7 +991,7 @@ "required": [ "name" ], - "additionalProperties": false, + "additionalProperties": true, "examples": [ { "description": "Example with both URL and name", @@ -1155,7 +1155,7 @@ "description": "Natural language query to select products from the brand manifest (e.g., 'all Kraft Heinz pasta sauces', 'organic products under $20')" } }, - "additionalProperties": false, + "additionalProperties": true, "examples": [ { "description": "Direct SKU selection for specific products from brand manifest", @@ -1219,7 +1219,7 @@ "required": [ "name" ], - "additionalProperties": false + "additionalProperties": true } }, "asset_selectors": { @@ -1261,13 +1261,13 @@ } } }, - "additionalProperties": false + "additionalProperties": true } }, "required": [ "brand_manifest" ], - "additionalProperties": false, + "additionalProperties": true, "examples": [ { "brand_manifest": { @@ -1320,12 +1320,12 @@ "required": [ "url" ], - "additionalProperties": false + "additionalProperties": true } ] } }, - "additionalProperties": false + "additionalProperties": true }, "inputs": { "type": "array", @@ -1352,7 +1352,7 @@ "required": [ "name" ], - "additionalProperties": false + "additionalProperties": true } }, "tags": { @@ -1387,7 +1387,7 @@ "format_id", "assets" ], - "additionalProperties": false + "additionalProperties": true }, "maxItems": 100 }, @@ -1421,7 +1421,7 @@ "required": [ "creative_id" ], - "additionalProperties": false + "additionalProperties": true } } }, @@ -1437,7 +1437,7 @@ ] } ], - "additionalProperties": false + "additionalProperties": true } }, "push_notification_config": { @@ -1517,9 +1517,9 @@ ] } ], - "additionalProperties": false, + "additionalProperties": true, "_bundled": { - "generatedAt": "2026-01-05T18:19:47.446Z", - "note": "This is a bundled schema with all $ref resolved inline." + "generatedAt": "2026-01-07T19:56:54.840Z", + "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/update-media-buy-response.json b/dist/schemas/2.6.0/bundled/media-buy/update-media-buy-response.json index 8579e96e80..23ebd57c19 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/update-media-buy-response.json +++ b/dist/schemas/2.6.0/bundled/media-buy/update-media-buy-response.json @@ -136,10 +136,10 @@ "required": [ "suppress_minutes" ], - "additionalProperties": false + "additionalProperties": true } }, - "additionalProperties": false + "additionalProperties": true }, "creative_assignments": { "type": "array", @@ -171,7 +171,7 @@ "required": [ "creative_id" ], - "additionalProperties": false + "additionalProperties": true } }, "format_ids_to_provide": { @@ -212,7 +212,7 @@ "agent_url", "id" ], - "additionalProperties": false, + "additionalProperties": true, "dependencies": { "width": [ "height" @@ -238,7 +238,7 @@ "required": [ "package_id" ], - "additionalProperties": false + "additionalProperties": true } }, "context": { @@ -258,7 +258,7 @@ "media_buy_id", "buyer_ref" ], - "additionalProperties": false, + "additionalProperties": true, "not": { "required": [ "errors" @@ -300,14 +300,16 @@ "minimum": 0 }, "details": { - "description": "Additional task-specific error details" + "type": "object", + "description": "Additional task-specific error details", + "additionalProperties": true } }, "required": [ "code", "message" ], - "additionalProperties": false + "additionalProperties": true }, "minItems": 1 }, @@ -327,7 +329,7 @@ "required": [ "errors" ], - "additionalProperties": false, + "additionalProperties": true, "not": { "anyOf": [ { @@ -350,7 +352,7 @@ } ], "_bundled": { - "generatedAt": "2026-01-05T18:19:47.447Z", - "note": "This is a bundled schema with all $ref resolved inline." + "generatedAt": "2026-01-07T19:56:54.841Z", + "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/signals/activate-signal-request.json b/dist/schemas/2.6.0/bundled/signals/activate-signal-request.json index 4b091ebe4d..24de122d6e 100644 --- a/dist/schemas/2.6.0/bundled/signals/activate-signal-request.json +++ b/dist/schemas/2.6.0/bundled/signals/activate-signal-request.json @@ -36,7 +36,7 @@ "type", "platform" ], - "additionalProperties": false + "additionalProperties": true }, { "type": "object", @@ -59,7 +59,7 @@ "type", "agent_url" ], - "additionalProperties": false + "additionalProperties": true } ] }, @@ -82,9 +82,9 @@ "signal_agent_segment_id", "deployments" ], - "additionalProperties": false, + "additionalProperties": true, "_bundled": { - "generatedAt": "2026-01-05T18:19:47.447Z", - "note": "This is a bundled schema with all $ref resolved inline." + "generatedAt": "2026-01-07T19:56:54.841Z", + "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/signals/activate-signal-response.json b/dist/schemas/2.6.0/bundled/signals/activate-signal-response.json index 63018d77ec..6e532f84b2 100644 --- a/dist/schemas/2.6.0/bundled/signals/activate-signal-response.json +++ b/dist/schemas/2.6.0/bundled/signals/activate-signal-response.json @@ -58,7 +58,7 @@ "type", "segment_id" ], - "additionalProperties": false + "additionalProperties": true }, { "properties": { @@ -81,7 +81,7 @@ "key", "value" ], - "additionalProperties": false + "additionalProperties": true } ] }, @@ -101,7 +101,7 @@ "platform", "is_live" ], - "additionalProperties": false + "additionalProperties": true }, { "type": "object", @@ -145,7 +145,7 @@ "type", "segment_id" ], - "additionalProperties": false + "additionalProperties": true }, { "properties": { @@ -168,7 +168,7 @@ "key", "value" ], - "additionalProperties": false + "additionalProperties": true } ] }, @@ -188,7 +188,7 @@ "agent_url", "is_live" ], - "additionalProperties": false + "additionalProperties": true } ] } @@ -209,7 +209,7 @@ "required": [ "deployments" ], - "additionalProperties": false, + "additionalProperties": true, "not": { "required": [ "errors" @@ -251,14 +251,16 @@ "minimum": 0 }, "details": { - "description": "Additional task-specific error details" + "type": "object", + "description": "Additional task-specific error details", + "additionalProperties": true } }, "required": [ "code", "message" ], - "additionalProperties": false + "additionalProperties": true }, "minItems": 1 }, @@ -278,7 +280,7 @@ "required": [ "errors" ], - "additionalProperties": false, + "additionalProperties": true, "not": { "required": [ "deployments" @@ -287,7 +289,7 @@ } ], "_bundled": { - "generatedAt": "2026-01-05T18:19:47.448Z", - "note": "This is a bundled schema with all $ref resolved inline." + "generatedAt": "2026-01-07T19:56:54.842Z", + "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/signals/get-signals-request.json b/dist/schemas/2.6.0/bundled/signals/get-signals-request.json index 9b49e8f9b1..85d7c3eb36 100644 --- a/dist/schemas/2.6.0/bundled/signals/get-signals-request.json +++ b/dist/schemas/2.6.0/bundled/signals/get-signals-request.json @@ -40,7 +40,7 @@ "type", "platform" ], - "additionalProperties": false + "additionalProperties": true }, { "type": "object", @@ -63,7 +63,7 @@ "type", "agent_url" ], - "additionalProperties": false + "additionalProperties": true } ] }, @@ -82,7 +82,7 @@ "deployments", "countries" ], - "additionalProperties": false + "additionalProperties": true }, "filters": { "title": "Signal Filters", @@ -122,7 +122,7 @@ "maximum": 100 } }, - "additionalProperties": false + "additionalProperties": true }, "max_results": { "type": "integer", @@ -146,9 +146,9 @@ "signal_spec", "deliver_to" ], - "additionalProperties": false, + "additionalProperties": true, "_bundled": { - "generatedAt": "2026-01-05T18:19:47.451Z", - "note": "This is a bundled schema with all $ref resolved inline." + "generatedAt": "2026-01-07T19:56:54.842Z", + "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/signals/get-signals-response.json b/dist/schemas/2.6.0/bundled/signals/get-signals-response.json index b382f9cfff..d7acb6f13f 100644 --- a/dist/schemas/2.6.0/bundled/signals/get-signals-response.json +++ b/dist/schemas/2.6.0/bundled/signals/get-signals-response.json @@ -91,7 +91,7 @@ "type", "segment_id" ], - "additionalProperties": false + "additionalProperties": true }, { "properties": { @@ -114,7 +114,7 @@ "key", "value" ], - "additionalProperties": false + "additionalProperties": true } ] }, @@ -134,7 +134,7 @@ "platform", "is_live" ], - "additionalProperties": false + "additionalProperties": true }, { "type": "object", @@ -178,7 +178,7 @@ "type", "segment_id" ], - "additionalProperties": false + "additionalProperties": true }, { "properties": { @@ -201,7 +201,7 @@ "key", "value" ], - "additionalProperties": false + "additionalProperties": true } ] }, @@ -221,7 +221,7 @@ "agent_url", "is_live" ], - "additionalProperties": false + "additionalProperties": true } ] } @@ -245,7 +245,7 @@ "cpm", "currency" ], - "additionalProperties": false + "additionalProperties": true } }, "required": [ @@ -258,7 +258,7 @@ "deployments", "pricing" ], - "additionalProperties": false + "additionalProperties": true } }, "errors": { @@ -291,14 +291,16 @@ "minimum": 0 }, "details": { - "description": "Additional task-specific error details" + "type": "object", + "description": "Additional task-specific error details", + "additionalProperties": true } }, "required": [ "code", "message" ], - "additionalProperties": false + "additionalProperties": true } }, "context": { @@ -317,9 +319,9 @@ "required": [ "signals" ], - "additionalProperties": false, + "additionalProperties": true, "_bundled": { - "generatedAt": "2026-01-05T18:19:47.452Z", - "note": "This is a bundled schema with all $ref resolved inline." + "generatedAt": "2026-01-07T19:56:54.842Z", + "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/core/activation-key.json b/dist/schemas/2.6.0/core/activation-key.json index 6d0d6d941d..67b3e2817c 100644 --- a/dist/schemas/2.6.0/core/activation-key.json +++ b/dist/schemas/2.6.0/core/activation-key.json @@ -17,8 +17,11 @@ "description": "The platform-specific segment identifier to use in campaign targeting" } }, - "required": ["type", "segment_id"], - "additionalProperties": false + "required": [ + "type", + "segment_id" + ], + "additionalProperties": true }, { "properties": { @@ -36,8 +39,12 @@ "description": "The targeting parameter value" } }, - "required": ["type", "key", "value"], - "additionalProperties": false + "required": [ + "type", + "key", + "value" + ], + "additionalProperties": true } ] } diff --git a/dist/schemas/2.6.0/core/assets/audio-asset.json b/dist/schemas/2.6.0/core/assets/audio-asset.json index d895834c41..8c48b4b4a4 100644 --- a/dist/schemas/2.6.0/core/assets/audio-asset.json +++ b/dist/schemas/2.6.0/core/assets/audio-asset.json @@ -25,6 +25,8 @@ "minimum": 1 } }, - "required": ["url"], - "additionalProperties": false + "required": [ + "url" + ], + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/core/assets/css-asset.json b/dist/schemas/2.6.0/core/assets/css-asset.json index bb69a9ba28..0d36107978 100644 --- a/dist/schemas/2.6.0/core/assets/css-asset.json +++ b/dist/schemas/2.6.0/core/assets/css-asset.json @@ -14,6 +14,8 @@ "description": "CSS media query context (e.g., 'screen', 'print')" } }, - "required": ["content"], - "additionalProperties": false + "required": [ + "content" + ], + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/core/assets/daast-asset.json b/dist/schemas/2.6.0/core/assets/daast-asset.json index 1039e4b43d..dfbbad197f 100644 --- a/dist/schemas/2.6.0/core/assets/daast-asset.json +++ b/dist/schemas/2.6.0/core/assets/daast-asset.json @@ -38,8 +38,11 @@ "description": "Whether companion display ads are included" } }, - "required": ["delivery_type", "url"], - "additionalProperties": false + "required": [ + "delivery_type", + "url" + ], + "additionalProperties": true }, { "type": "object", @@ -74,8 +77,11 @@ "description": "Whether companion display ads are included" } }, - "required": ["delivery_type", "content"], - "additionalProperties": false + "required": [ + "delivery_type", + "content" + ], + "additionalProperties": true } ] } diff --git a/dist/schemas/2.6.0/core/assets/html-asset.json b/dist/schemas/2.6.0/core/assets/html-asset.json index 7849f43d77..df1ba91c58 100644 --- a/dist/schemas/2.6.0/core/assets/html-asset.json +++ b/dist/schemas/2.6.0/core/assets/html-asset.json @@ -14,6 +14,8 @@ "description": "HTML version (e.g., 'HTML5')" } }, - "required": ["content"], - "additionalProperties": false + "required": [ + "content" + ], + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/core/assets/image-asset.json b/dist/schemas/2.6.0/core/assets/image-asset.json index 245ebbca3a..953598f30a 100644 --- a/dist/schemas/2.6.0/core/assets/image-asset.json +++ b/dist/schemas/2.6.0/core/assets/image-asset.json @@ -29,6 +29,10 @@ "description": "Alternative text for accessibility" } }, - "required": ["url", "width", "height"], - "additionalProperties": false + "required": [ + "url", + "width", + "height" + ], + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/core/assets/javascript-asset.json b/dist/schemas/2.6.0/core/assets/javascript-asset.json index 09eb42614b..7c7cb94ed8 100644 --- a/dist/schemas/2.6.0/core/assets/javascript-asset.json +++ b/dist/schemas/2.6.0/core/assets/javascript-asset.json @@ -14,6 +14,8 @@ "description": "JavaScript module type" } }, - "required": ["content"], - "additionalProperties": false + "required": [ + "content" + ], + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/core/assets/markdown-asset.json b/dist/schemas/2.6.0/core/assets/markdown-asset.json index efcf4ff69b..de825fd86f 100644 --- a/dist/schemas/2.6.0/core/assets/markdown-asset.json +++ b/dist/schemas/2.6.0/core/assets/markdown-asset.json @@ -24,6 +24,8 @@ "description": "Whether raw HTML blocks are allowed in the markdown. False recommended for security." } }, - "required": ["content"], - "additionalProperties": false + "required": [ + "content" + ], + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/core/assets/text-asset.json b/dist/schemas/2.6.0/core/assets/text-asset.json index 0a459194e1..0fdd358ddd 100644 --- a/dist/schemas/2.6.0/core/assets/text-asset.json +++ b/dist/schemas/2.6.0/core/assets/text-asset.json @@ -14,6 +14,8 @@ "description": "Language code (e.g., 'en', 'es', 'fr')" } }, - "required": ["content"], - "additionalProperties": false + "required": [ + "content" + ], + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/core/assets/url-asset.json b/dist/schemas/2.6.0/core/assets/url-asset.json index 4276e8d2d8..2a2d44da44 100644 --- a/dist/schemas/2.6.0/core/assets/url-asset.json +++ b/dist/schemas/2.6.0/core/assets/url-asset.json @@ -19,6 +19,8 @@ "description": "Description of what this URL points to" } }, - "required": ["url"], - "additionalProperties": false + "required": [ + "url" + ], + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/core/assets/vast-asset.json b/dist/schemas/2.6.0/core/assets/vast-asset.json index 4bfef29e0d..a4c3d5d4b3 100644 --- a/dist/schemas/2.6.0/core/assets/vast-asset.json +++ b/dist/schemas/2.6.0/core/assets/vast-asset.json @@ -38,8 +38,11 @@ "description": "Tracking events supported by this VAST tag" } }, - "required": ["delivery_type", "url"], - "additionalProperties": false + "required": [ + "delivery_type", + "url" + ], + "additionalProperties": true }, { "type": "object", @@ -74,8 +77,11 @@ "description": "Tracking events supported by this VAST tag" } }, - "required": ["delivery_type", "content"], - "additionalProperties": false + "required": [ + "delivery_type", + "content" + ], + "additionalProperties": true } ] } diff --git a/dist/schemas/2.6.0/core/assets/video-asset.json b/dist/schemas/2.6.0/core/assets/video-asset.json index a47ebd686a..f25f7a34f6 100644 --- a/dist/schemas/2.6.0/core/assets/video-asset.json +++ b/dist/schemas/2.6.0/core/assets/video-asset.json @@ -35,6 +35,10 @@ "minimum": 1 } }, - "required": ["url", "width", "height"], - "additionalProperties": false + "required": [ + "url", + "width", + "height" + ], + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/core/assets/webhook-asset.json b/dist/schemas/2.6.0/core/assets/webhook-asset.json index 235d12283c..e19570f383 100644 --- a/dist/schemas/2.6.0/core/assets/webhook-asset.json +++ b/dist/schemas/2.6.0/core/assets/webhook-asset.json @@ -57,9 +57,15 @@ "description": "Header name for API key (e.g., 'X-API-Key')" } }, - "required": ["method"] + "required": [ + "method" + ] } }, - "required": ["url", "response_type", "security"], - "additionalProperties": false + "required": [ + "url", + "response_type", + "security" + ], + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/core/async-response-data.json b/dist/schemas/2.6.0/core/async-response-data.json index f7f2334272..5ce383d420 100644 --- a/dist/schemas/2.6.0/core/async-response-data.json +++ b/dist/schemas/2.6.0/core/async-response-data.json @@ -86,4 +86,3 @@ } ] } - diff --git a/dist/schemas/2.6.0/core/brand-manifest.json b/dist/schemas/2.6.0/core/brand-manifest.json index 8192be555d..92a3e69f75 100644 --- a/dist/schemas/2.6.0/core/brand-manifest.json +++ b/dist/schemas/2.6.0/core/brand-manifest.json @@ -41,7 +41,9 @@ "description": "Logo height in pixels" } }, - "required": ["url"] + "required": [ + "url" + ] } }, "colors": { @@ -165,8 +167,12 @@ "additionalProperties": true } }, - "required": ["asset_id", "asset_type", "url"], - "additionalProperties": false + "required": [ + "asset_id", + "asset_type", + "url" + ], + "additionalProperties": true } }, "product_catalog": { @@ -180,7 +186,11 @@ }, "feed_format": { "type": "string", - "enum": ["google_merchant_center", "facebook_catalog", "custom"], + "enum": [ + "google_merchant_center", + "facebook_catalog", + "custom" + ], "default": "google_merchant_center", "description": "Format of the product feed" }, @@ -198,12 +208,19 @@ }, "update_frequency": { "type": "string", - "enum": ["realtime", "hourly", "daily", "weekly"], + "enum": [ + "realtime", + "hourly", + "daily", + "weekly" + ], "description": "How frequently the product catalog is updated" } }, - "required": ["feed_url"], - "additionalProperties": false + "required": [ + "feed_url" + ], + "additionalProperties": true }, "disclaimers": { "type": "array", @@ -225,7 +242,9 @@ "default": true } }, - "required": ["text"] + "required": [ + "text" + ] } }, "industry": { @@ -272,8 +291,10 @@ } } }, - "required": ["name"], - "additionalProperties": false, + "required": [ + "name" + ], + "additionalProperties": true, "examples": [ { "description": "Example with both URL and name", @@ -299,71 +320,89 @@ "url": "https://acmecorp.com", "name": "ACME Corporation", "logos": [ - { - "url": "https://cdn.acmecorp.com/logo-square-dark.png", - "tags": ["dark", "square"], - "width": 512, - "height": 512 + { + "url": "https://cdn.acmecorp.com/logo-square-dark.png", + "tags": [ + "dark", + "square" + ], + "width": 512, + "height": 512 + }, + { + "url": "https://cdn.acmecorp.com/logo-horizontal-light.png", + "tags": [ + "light", + "horizontal" + ], + "width": 1200, + "height": 400 + } + ], + "colors": { + "primary": "#FF6B35", + "secondary": "#004E89", + "accent": "#F7931E", + "background": "#FFFFFF", + "text": "#1A1A1A" }, - { - "url": "https://cdn.acmecorp.com/logo-horizontal-light.png", - "tags": ["light", "horizontal"], - "width": 1200, - "height": 400 - } - ], - "colors": { - "primary": "#FF6B35", - "secondary": "#004E89", - "accent": "#F7931E", - "background": "#FFFFFF", - "text": "#1A1A1A" - }, - "fonts": { - "primary": "Helvetica Neue", - "secondary": "Georgia" - }, - "tone": "professional and trustworthy", - "tagline": "Innovation You Can Trust", - "assets": [ - { - "asset_id": "hero_winter_2024", - "asset_type": "image", - "url": "https://cdn.acmecorp.com/hero-winter-2024.jpg", - "tags": ["hero", "winter", "holiday", "lifestyle"], - "name": "Winter Campaign Hero", - "width": 1920, - "height": 1080, - "format": "jpg" + "fonts": { + "primary": "Helvetica Neue", + "secondary": "Georgia" }, - { - "asset_id": "product_video_30s", - "asset_type": "video", - "url": "https://cdn.acmecorp.com/product-demo-30s.mp4", - "tags": ["product", "demo", "30s"], - "name": "Product Demo 30 Second", - "width": 1920, - "height": 1080, - "duration_seconds": 30, - "format": "mp4" - } - ], - "product_catalog": { - "feed_url": "https://acmecorp.com/products.xml", - "feed_format": "google_merchant_center", - "categories": ["electronics/computers", "electronics/accessories"], - "last_updated": "2024-03-15T10:00:00Z", - "update_frequency": "hourly" - }, - "disclaimers": [ - { - "text": "Results may vary. Consult a professional before use.", - "context": "health_claims", - "required": true - } - ], - "industry": "technology", - "target_audience": "business decision-makers aged 35-55" + "tone": "professional and trustworthy", + "tagline": "Innovation You Can Trust", + "assets": [ + { + "asset_id": "hero_winter_2024", + "asset_type": "image", + "url": "https://cdn.acmecorp.com/hero-winter-2024.jpg", + "tags": [ + "hero", + "winter", + "holiday", + "lifestyle" + ], + "name": "Winter Campaign Hero", + "width": 1920, + "height": 1080, + "format": "jpg" + }, + { + "asset_id": "product_video_30s", + "asset_type": "video", + "url": "https://cdn.acmecorp.com/product-demo-30s.mp4", + "tags": [ + "product", + "demo", + "30s" + ], + "name": "Product Demo 30 Second", + "width": 1920, + "height": 1080, + "duration_seconds": 30, + "format": "mp4" + } + ], + "product_catalog": { + "feed_url": "https://acmecorp.com/products.xml", + "feed_format": "google_merchant_center", + "categories": [ + "electronics/computers", + "electronics/accessories" + ], + "last_updated": "2024-03-15T10:00:00Z", + "update_frequency": "hourly" + }, + "disclaimers": [ + { + "text": "Results may vary. Consult a professional before use.", + "context": "health_claims", + "required": true + } + ], + "industry": "technology", + "target_audience": "business decision-makers aged 35-55" } } ] diff --git a/dist/schemas/2.6.0/core/creative-asset.json b/dist/schemas/2.6.0/core/creative-asset.json index d3ca9a1615..37a5d24868 100644 --- a/dist/schemas/2.6.0/core/creative-asset.json +++ b/dist/schemas/2.6.0/core/creative-asset.json @@ -23,21 +23,43 @@ "patternProperties": { "^[a-zA-Z0-9_-]+$": { "oneOf": [ - {"$ref": "/schemas/2.6.0/core/assets/image-asset.json"}, - {"$ref": "/schemas/2.6.0/core/assets/video-asset.json"}, - {"$ref": "/schemas/2.6.0/core/assets/audio-asset.json"}, - {"$ref": "/schemas/2.6.0/core/assets/text-asset.json"}, - {"$ref": "/schemas/2.6.0/core/assets/html-asset.json"}, - {"$ref": "/schemas/2.6.0/core/assets/css-asset.json"}, - {"$ref": "/schemas/2.6.0/core/assets/javascript-asset.json"}, - {"$ref": "/schemas/2.6.0/core/assets/vast-asset.json"}, - {"$ref": "/schemas/2.6.0/core/assets/daast-asset.json"}, - {"$ref": "/schemas/2.6.0/core/promoted-offerings.json"}, - {"$ref": "/schemas/2.6.0/core/assets/url-asset.json"} + { + "$ref": "/schemas/2.6.0/core/assets/image-asset.json" + }, + { + "$ref": "/schemas/2.6.0/core/assets/video-asset.json" + }, + { + "$ref": "/schemas/2.6.0/core/assets/audio-asset.json" + }, + { + "$ref": "/schemas/2.6.0/core/assets/text-asset.json" + }, + { + "$ref": "/schemas/2.6.0/core/assets/html-asset.json" + }, + { + "$ref": "/schemas/2.6.0/core/assets/css-asset.json" + }, + { + "$ref": "/schemas/2.6.0/core/assets/javascript-asset.json" + }, + { + "$ref": "/schemas/2.6.0/core/assets/vast-asset.json" + }, + { + "$ref": "/schemas/2.6.0/core/assets/daast-asset.json" + }, + { + "$ref": "/schemas/2.6.0/core/promoted-offerings.json" + }, + { + "$ref": "/schemas/2.6.0/core/assets/url-asset.json" + } ] } }, - "additionalProperties": false + "additionalProperties": true }, "inputs": { "type": "array", @@ -52,15 +74,19 @@ "macros": { "type": "object", "description": "Macro values to apply for this preview", - "additionalProperties": {"type": "string"} + "additionalProperties": { + "type": "string" + } }, "context_description": { "type": "string", "description": "Natural language description of the context for AI-generated content" } }, - "required": ["name"], - "additionalProperties": false + "required": [ + "name" + ], + "additionalProperties": true } }, "tags": { @@ -89,6 +115,11 @@ "minItems": 1 } }, - "required": ["creative_id", "name", "format_id", "assets"], - "additionalProperties": false -} \ No newline at end of file + "required": [ + "creative_id", + "name", + "format_id", + "assets" + ], + "additionalProperties": true +} diff --git a/dist/schemas/2.6.0/core/creative-assignment.json b/dist/schemas/2.6.0/core/creative-assignment.json index 5c39fb1d59..e21ba19216 100644 --- a/dist/schemas/2.6.0/core/creative-assignment.json +++ b/dist/schemas/2.6.0/core/creative-assignment.json @@ -24,6 +24,8 @@ "minItems": 1 } }, - "required": ["creative_id"], - "additionalProperties": false -} \ No newline at end of file + "required": [ + "creative_id" + ], + "additionalProperties": true +} diff --git a/dist/schemas/2.6.0/core/creative-filters.json b/dist/schemas/2.6.0/core/creative-filters.json index 2c167a8b90..9d27db988d 100644 --- a/dist/schemas/2.6.0/core/creative-filters.json +++ b/dist/schemas/2.6.0/core/creative-filters.json @@ -107,5 +107,5 @@ "description": "Filter creatives that have performance data when true" } }, - "additionalProperties": false + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/core/creative-manifest.json b/dist/schemas/2.6.0/core/creative-manifest.json index acd9cfea1e..91b76b9521 100644 --- a/dist/schemas/2.6.0/core/creative-manifest.json +++ b/dist/schemas/2.6.0/core/creative-manifest.json @@ -58,7 +58,7 @@ ] } }, - "additionalProperties": false + "additionalProperties": true }, "ext": { "$ref": "/schemas/2.6.0/core/ext.json" @@ -68,5 +68,5 @@ "format_id", "assets" ], - "additionalProperties": false + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/core/creative-policy.json b/dist/schemas/2.6.0/core/creative-policy.json index cbf64b262e..663add85a0 100644 --- a/dist/schemas/2.6.0/core/creative-policy.json +++ b/dist/schemas/2.6.0/core/creative-policy.json @@ -18,6 +18,10 @@ "description": "Whether creative templates are provided" } }, - "required": ["co_branding", "landing_page", "templates_available"], - "additionalProperties": false -} \ No newline at end of file + "required": [ + "co_branding", + "landing_page", + "templates_available" + ], + "additionalProperties": true +} diff --git a/dist/schemas/2.6.0/core/delivery-metrics.json b/dist/schemas/2.6.0/core/delivery-metrics.json index d3d4bb9922..660f3c12b8 100644 --- a/dist/schemas/2.6.0/core/delivery-metrics.json +++ b/dist/schemas/2.6.0/core/delivery-metrics.json @@ -156,12 +156,15 @@ "minimum": 0 } }, - "required": ["venue_id", "impressions"], - "additionalProperties": false + "required": [ + "venue_id", + "impressions" + ], + "additionalProperties": true } } }, - "additionalProperties": false + "additionalProperties": true } }, "additionalProperties": true diff --git a/dist/schemas/2.6.0/core/deployment.json b/dist/schemas/2.6.0/core/deployment.json index 58fa211e54..bab2e716e9 100644 --- a/dist/schemas/2.6.0/core/deployment.json +++ b/dist/schemas/2.6.0/core/deployment.json @@ -39,8 +39,12 @@ "description": "Timestamp when activation completed (if is_live=true)" } }, - "required": ["type", "platform", "is_live"], - "additionalProperties": false + "required": [ + "type", + "platform", + "is_live" + ], + "additionalProperties": true }, { "type": "object", @@ -78,8 +82,12 @@ "description": "Timestamp when activation completed (if is_live=true)" } }, - "required": ["type", "agent_url", "is_live"], - "additionalProperties": false + "required": [ + "type", + "agent_url", + "is_live" + ], + "additionalProperties": true } ] } diff --git a/dist/schemas/2.6.0/core/destination.json b/dist/schemas/2.6.0/core/destination.json index 1cc303a471..a3ddae6bb9 100644 --- a/dist/schemas/2.6.0/core/destination.json +++ b/dist/schemas/2.6.0/core/destination.json @@ -20,8 +20,11 @@ "description": "Optional account identifier on the platform" } }, - "required": ["type", "platform"], - "additionalProperties": false + "required": [ + "type", + "platform" + ], + "additionalProperties": true }, { "type": "object", @@ -40,8 +43,11 @@ "description": "Optional account identifier on the agent" } }, - "required": ["type", "agent_url"], - "additionalProperties": false + "required": [ + "type", + "agent_url" + ], + "additionalProperties": true } ] } diff --git a/dist/schemas/2.6.0/core/error.json b/dist/schemas/2.6.0/core/error.json index cd6f83dbc2..feef52fdf7 100644 --- a/dist/schemas/2.6.0/core/error.json +++ b/dist/schemas/2.6.0/core/error.json @@ -27,9 +27,14 @@ "minimum": 0 }, "details": { - "description": "Additional task-specific error details" + "type": "object", + "description": "Additional task-specific error details", + "additionalProperties": true } }, - "required": ["code", "message"], - "additionalProperties": false -} \ No newline at end of file + "required": [ + "code", + "message" + ], + "additionalProperties": true +} diff --git a/dist/schemas/2.6.0/core/format-id.json b/dist/schemas/2.6.0/core/format-id.json index a47080b219..235caae4fd 100644 --- a/dist/schemas/2.6.0/core/format-id.json +++ b/dist/schemas/2.6.0/core/format-id.json @@ -31,10 +31,17 @@ "description": "Duration in milliseconds for time-based formats (video, audio). When specified, creates a parameterized format ID. Omit to reference a template format without parameters." } }, - "required": ["agent_url", "id"], - "additionalProperties": false, + "required": [ + "agent_url", + "id" + ], + "additionalProperties": true, "dependencies": { - "width": ["height"], - "height": ["width"] + "width": [ + "height" + ], + "height": [ + "width" + ] } } diff --git a/dist/schemas/2.6.0/core/format.json b/dist/schemas/2.6.0/core/format.json index ab8999a800..e824efe5dc 100644 --- a/dist/schemas/2.6.0/core/format.json +++ b/dist/schemas/2.6.0/core/format.json @@ -91,10 +91,17 @@ "type": "object", "description": "Indicates which dimensions are responsive/fluid", "properties": { - "width": {"type": "boolean"}, - "height": {"type": "boolean"} + "width": { + "type": "boolean" + }, + "height": { + "type": "boolean" + } }, - "required": ["width", "height"] + "required": [ + "width", + "height" + ] }, "aspect_ratio": { "type": "string", @@ -104,16 +111,34 @@ } } }, - "required": ["role"], + "required": [ + "role" + ], "oneOf": [ { - "required": ["dimensions"], - "not": {"required": ["parameters_from_format_id"]} + "required": [ + "dimensions" + ], + "not": { + "required": [ + "parameters_from_format_id" + ] + } }, { - "required": ["parameters_from_format_id"], - "properties": {"parameters_from_format_id": {"const": true}}, - "not": {"required": ["dimensions"]} + "required": [ + "parameters_from_format_id" + ], + "properties": { + "parameters_from_format_id": { + "const": true + } + }, + "not": { + "required": [ + "dimensions" + ] + } } ] }, @@ -144,7 +169,7 @@ }, "asset_role": { "type": "string", - "description": "Optional descriptive label for this asset's purpose (e.g., 'hero_image', 'logo'). Not used for referencing assets in manifests—use asset_id instead. This field is for human-readable documentation and UI display only." + "description": "Optional descriptive label for this asset's purpose (e.g., 'hero_image', 'logo'). Not used for referencing assets in manifests\u2014use asset_id instead. This field is for human-readable documentation and UI display only." }, "required": { "type": "boolean", @@ -156,7 +181,11 @@ "additionalProperties": true } }, - "required": ["item_type", "asset_id", "asset_type"] + "required": [ + "item_type", + "asset_id", + "asset_type" + ] }, { "description": "Repeatable asset group (for carousels, slideshows, playlists, etc.)", @@ -197,7 +226,7 @@ }, "asset_role": { "type": "string", - "description": "Optional descriptive label for this asset's purpose (e.g., 'hero_image', 'logo'). Not used for referencing assets in manifests—use asset_id instead. This field is for human-readable documentation and UI display only." + "description": "Optional descriptive label for this asset's purpose (e.g., 'hero_image', 'logo'). Not used for referencing assets in manifests\u2014use asset_id instead. This field is for human-readable documentation and UI display only." }, "required": { "type": "boolean", @@ -209,11 +238,20 @@ "additionalProperties": true } }, - "required": ["asset_id", "asset_type"] + "required": [ + "asset_id", + "asset_type" + ] } } }, - "required": ["item_type", "asset_group_id", "min_count", "max_count", "assets"] + "required": [ + "item_type", + "asset_group_id", + "min_count", + "max_count", + "assets" + ] } ] } @@ -354,8 +392,11 @@ "additionalProperties": true } }, - "required": ["format_id", "manifest"], - "additionalProperties": false + "required": [ + "format_id", + "manifest" + ], + "additionalProperties": true }, "format_card_detailed": { "type": "object", @@ -371,10 +412,17 @@ "additionalProperties": true } }, - "required": ["format_id", "manifest"], - "additionalProperties": false + "required": [ + "format_id", + "manifest" + ], + "additionalProperties": true } }, - "required": ["format_id", "name", "type"], - "additionalProperties": false -} \ No newline at end of file + "required": [ + "format_id", + "name", + "type" + ], + "additionalProperties": true +} diff --git a/dist/schemas/2.6.0/core/frequency-cap.json b/dist/schemas/2.6.0/core/frequency-cap.json index 5aeb769f62..682b4dcbd5 100644 --- a/dist/schemas/2.6.0/core/frequency-cap.json +++ b/dist/schemas/2.6.0/core/frequency-cap.json @@ -11,6 +11,8 @@ "minimum": 0 } }, - "required": ["suppress_minutes"], - "additionalProperties": false -} \ No newline at end of file + "required": [ + "suppress_minutes" + ], + "additionalProperties": true +} diff --git a/dist/schemas/2.6.0/core/mcp-webhook-payload.json b/dist/schemas/2.6.0/core/mcp-webhook-payload.json index 076fe3cbf2..8ec58d76a2 100644 --- a/dist/schemas/2.6.0/core/mcp-webhook-payload.json +++ b/dist/schemas/2.6.0/core/mcp-webhook-payload.json @@ -43,7 +43,12 @@ "description": "Task-specific payload matching the status. For completed/failed, contains the full task response. For working/input-required/submitted, contains status-specific data. This is the data layer that AdCP specs - same structure used in A2A status.message.parts[].data." } }, - "required": ["task_id", "task_type", "status", "timestamp"], + "required": [ + "task_id", + "task_type", + "status", + "timestamp" + ], "additionalProperties": true, "examples": [ { diff --git a/dist/schemas/2.6.0/core/measurement.json b/dist/schemas/2.6.0/core/measurement.json index c2c9bdcb8c..2d8d405900 100644 --- a/dist/schemas/2.6.0/core/measurement.json +++ b/dist/schemas/2.6.0/core/measurement.json @@ -8,24 +8,41 @@ "type": { "type": "string", "description": "Type of measurement", - "examples": ["incremental_sales_lift", "brand_lift", "foot_traffic"] + "examples": [ + "incremental_sales_lift", + "brand_lift", + "foot_traffic" + ] }, "attribution": { "type": "string", "description": "Attribution methodology", - "examples": ["deterministic_purchase", "probabilistic"] + "examples": [ + "deterministic_purchase", + "probabilistic" + ] }, "window": { "type": "string", "description": "Attribution window", - "examples": ["30_days", "7_days"] + "examples": [ + "30_days", + "7_days" + ] }, "reporting": { "type": "string", "description": "Reporting frequency and format", - "examples": ["weekly_dashboard", "real_time_api"] + "examples": [ + "weekly_dashboard", + "real_time_api" + ] } }, - "required": ["type", "attribution", "reporting"], - "additionalProperties": false -} \ No newline at end of file + "required": [ + "type", + "attribution", + "reporting" + ], + "additionalProperties": true +} diff --git a/dist/schemas/2.6.0/core/media-buy.json b/dist/schemas/2.6.0/core/media-buy.json index 233411205f..dc5e1a5f59 100644 --- a/dist/schemas/2.6.0/core/media-buy.json +++ b/dist/schemas/2.6.0/core/media-buy.json @@ -58,5 +58,5 @@ "total_budget", "packages" ], - "additionalProperties": false + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/core/package.json b/dist/schemas/2.6.0/core/package.json index 24fc457003..9c736e9388 100644 --- a/dist/schemas/2.6.0/core/package.json +++ b/dist/schemas/2.6.0/core/package.json @@ -68,5 +68,5 @@ "required": [ "package_id" ], - "additionalProperties": false + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/core/performance-feedback.json b/dist/schemas/2.6.0/core/performance-feedback.json index 2df893bda1..c561f7e307 100644 --- a/dist/schemas/2.6.0/core/performance-feedback.json +++ b/dist/schemas/2.6.0/core/performance-feedback.json @@ -36,8 +36,11 @@ "description": "ISO 8601 end timestamp for measurement period" } }, - "required": ["start", "end"], - "additionalProperties": false + "required": [ + "start", + "end" + ], + "additionalProperties": true }, "performance_index": { "type": "number", @@ -55,7 +58,12 @@ "status": { "type": "string", "description": "Processing status of the performance feedback", - "enum": ["accepted", "queued", "applied", "rejected"] + "enum": [ + "accepted", + "queued", + "applied", + "rejected" + ] }, "submitted_at": { "type": "string", @@ -78,5 +86,5 @@ "status", "submitted_at" ], - "additionalProperties": false -} \ No newline at end of file + "additionalProperties": true +} diff --git a/dist/schemas/2.6.0/core/placement.json b/dist/schemas/2.6.0/core/placement.json index 200f525dd2..812e2ab610 100644 --- a/dist/schemas/2.6.0/core/placement.json +++ b/dist/schemas/2.6.0/core/placement.json @@ -26,6 +26,9 @@ "minItems": 1 } }, - "required": ["placement_id", "name"], - "additionalProperties": false + "required": [ + "placement_id", + "name" + ], + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/core/product-filters.json b/dist/schemas/2.6.0/core/product-filters.json index 7019a3333e..5f10c19eee 100644 --- a/dist/schemas/2.6.0/core/product-filters.json +++ b/dist/schemas/2.6.0/core/product-filters.json @@ -65,12 +65,22 @@ "pattern": "^[A-Z]{3}$" } }, - "required": ["currency"], + "required": [ + "currency" + ], "anyOf": [ - {"required": ["min"]}, - {"required": ["max"]} + { + "required": [ + "min" + ] + }, + { + "required": [ + "max" + ] + } ], - "additionalProperties": false + "additionalProperties": true }, "countries": { "type": "array", @@ -88,5 +98,5 @@ } } }, - "additionalProperties": false + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/core/product.json b/dist/schemas/2.6.0/core/product.json index f8a5c8f598..04b13a22a2 100644 --- a/dist/schemas/2.6.0/core/product.json +++ b/dist/schemas/2.6.0/core/product.json @@ -113,7 +113,7 @@ "format_id", "manifest" ], - "additionalProperties": false + "additionalProperties": true }, "product_card_detailed": { "type": "object", @@ -133,7 +133,7 @@ "format_id", "manifest" ], - "additionalProperties": false + "additionalProperties": true }, "ext": { "$ref": "/schemas/2.6.0/core/ext.json" @@ -149,5 +149,5 @@ "delivery_measurement", "pricing_options" ], - "additionalProperties": false + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/core/promoted-offerings.json b/dist/schemas/2.6.0/core/promoted-offerings.json index 2e312029c4..d465e6d1e2 100644 --- a/dist/schemas/2.6.0/core/promoted-offerings.json +++ b/dist/schemas/2.6.0/core/promoted-offerings.json @@ -37,8 +37,10 @@ } } }, - "required": ["name"], - "additionalProperties": false + "required": [ + "name" + ], + "additionalProperties": true } }, "asset_selectors": { @@ -57,7 +59,19 @@ "description": "Filter by asset type (e.g., ['image', 'video'])", "items": { "type": "string", - "enum": ["image", "video", "audio", "vast", "daast", "text", "url", "html", "css", "javascript", "webhook"] + "enum": [ + "image", + "video", + "audio", + "vast", + "daast", + "text", + "url", + "html", + "css", + "javascript", + "webhook" + ] } }, "exclude_tags": { @@ -68,11 +82,13 @@ } } }, - "additionalProperties": false + "additionalProperties": true } }, - "required": ["brand_manifest"], - "additionalProperties": false, + "required": [ + "brand_manifest" + ], + "additionalProperties": true, "examples": [ { "brand_manifest": { @@ -80,11 +96,19 @@ "url": "https://brand.com" }, "product_selectors": { - "manifest_skus": ["SKU-123", "SKU-456"] + "manifest_skus": [ + "SKU-123", + "SKU-456" + ] }, "asset_selectors": { - "tags": ["holiday"], - "asset_types": ["image", "video"] + "tags": [ + "holiday" + ], + "asset_types": [ + "image", + "video" + ] } } ] diff --git a/dist/schemas/2.6.0/core/promoted-products.json b/dist/schemas/2.6.0/core/promoted-products.json index 4a1dceafb6..451197fbb4 100644 --- a/dist/schemas/2.6.0/core/promoted-products.json +++ b/dist/schemas/2.6.0/core/promoted-products.json @@ -28,18 +28,24 @@ "description": "Natural language query to select products from the brand manifest (e.g., 'all Kraft Heinz pasta sauces', 'organic products under $20')" } }, - "additionalProperties": false, + "additionalProperties": true, "examples": [ { "description": "Direct SKU selection for specific products from brand manifest", "data": { - "manifest_skus": ["SKU-12345", "SKU-67890"] + "manifest_skus": [ + "SKU-12345", + "SKU-67890" + ] } }, { "description": "UNION selection: products tagged 'organic' OR 'sauces' OR in 'food/condiments' category from brand manifest", "data": { - "manifest_tags": ["organic", "sauces"], + "manifest_tags": [ + "organic", + "sauces" + ], "manifest_category": "food/condiments" } }, @@ -52,7 +58,9 @@ { "description": "Select products by tags", "data": { - "manifest_tags": ["holiday"] + "manifest_tags": [ + "holiday" + ] } } ] diff --git a/dist/schemas/2.6.0/core/property-id.json b/dist/schemas/2.6.0/core/property-id.json index c06fd5a395..35df52aa47 100644 --- a/dist/schemas/2.6.0/core/property-id.json +++ b/dist/schemas/2.6.0/core/property-id.json @@ -5,5 +5,10 @@ "description": "Identifier for a publisher property. Must be lowercase alphanumeric with underscores only.", "type": "string", "pattern": "^[a-z0-9_]+$", - "examples": ["cnn_ctv_app", "homepage", "mobile_ios", "instagram"] + "examples": [ + "cnn_ctv_app", + "homepage", + "mobile_ios", + "instagram" + ] } diff --git a/dist/schemas/2.6.0/core/property-tag.json b/dist/schemas/2.6.0/core/property-tag.json index c7907f6d2c..7acf065931 100644 --- a/dist/schemas/2.6.0/core/property-tag.json +++ b/dist/schemas/2.6.0/core/property-tag.json @@ -5,5 +5,12 @@ "description": "Tag for categorizing publisher properties. Must be lowercase alphanumeric with underscores only.", "type": "string", "pattern": "^[a-z0-9_]+$", - "examples": ["ctv", "premium", "news", "sports", "meta_network", "social_media"] + "examples": [ + "ctv", + "premium", + "news", + "sports", + "meta_network", + "social_media" + ] } diff --git a/dist/schemas/2.6.0/core/property.json b/dist/schemas/2.6.0/core/property.json index e7333f5a21..9c617af973 100644 --- a/dist/schemas/2.6.0/core/property.json +++ b/dist/schemas/2.6.0/core/property.json @@ -32,8 +32,11 @@ "description": "The identifier value. For domain type: 'example.com' matches base domain plus www and m subdomains; 'edition.example.com' matches that specific subdomain; '*.example.com' matches ALL subdomains but NOT base domain" } }, - "required": ["type", "value"], - "additionalProperties": false + "required": [ + "type", + "value" + ], + "additionalProperties": true }, "minItems": 1 }, @@ -50,6 +53,10 @@ "description": "Domain where adagents.json should be checked for authorization validation. Required for list_authorized_properties response. Optional in adagents.json (file location implies domain)." } }, - "required": ["property_type", "name", "identifiers"], - "additionalProperties": false -} \ No newline at end of file + "required": [ + "property_type", + "name", + "identifiers" + ], + "additionalProperties": true +} diff --git a/dist/schemas/2.6.0/core/protocol-envelope.json b/dist/schemas/2.6.0/core/protocol-envelope.json index 32d1304ed7..a82988a643 100644 --- a/dist/schemas/2.6.0/core/protocol-envelope.json +++ b/dist/schemas/2.6.0/core/protocol-envelope.json @@ -40,7 +40,7 @@ "status", "payload" ], - "additionalProperties": false, + "additionalProperties": true, "examples": [ { "description": "Synchronous task response with immediate results", @@ -57,7 +57,7 @@ "description": "Premium connected TV inventory across California", "pricing": { "model": "cpm", - "amount": 45.00, + "amount": 45.0, "currency": "USD" } } @@ -76,7 +76,9 @@ "push_notification_config": { "url": "https://buyer.example.com/webhooks/adcp", "authentication": { - "schemes": ["HMAC-SHA256"], + "schemes": [ + "HMAC-SHA256" + ], "credentials": "shared_secret_exchanged_during_onboarding_min_32_chars" } }, diff --git a/dist/schemas/2.6.0/core/publisher-property-selector.json b/dist/schemas/2.6.0/core/publisher-property-selector.json index 8a9158fac3..6a7c1ea562 100644 --- a/dist/schemas/2.6.0/core/publisher-property-selector.json +++ b/dist/schemas/2.6.0/core/publisher-property-selector.json @@ -22,8 +22,11 @@ "description": "Discriminator indicating all properties from this publisher are included" } }, - "required": ["publisher_domain", "selection_type"], - "additionalProperties": false + "required": [ + "publisher_domain", + "selection_type" + ], + "additionalProperties": true }, { "type": "object", @@ -48,8 +51,12 @@ "minItems": 1 } }, - "required": ["publisher_domain", "selection_type", "property_ids"], - "additionalProperties": false + "required": [ + "publisher_domain", + "selection_type", + "property_ids" + ], + "additionalProperties": true }, { "type": "object", @@ -74,8 +81,12 @@ "minItems": 1 } }, - "required": ["publisher_domain", "selection_type", "property_tags"], - "additionalProperties": false + "required": [ + "publisher_domain", + "selection_type", + "property_tags" + ], + "additionalProperties": true } ] } diff --git a/dist/schemas/2.6.0/core/push-notification-config.json b/dist/schemas/2.6.0/core/push-notification-config.json index 4e3d29b53c..421bce6237 100644 --- a/dist/schemas/2.6.0/core/push-notification-config.json +++ b/dist/schemas/2.6.0/core/push-notification-config.json @@ -34,9 +34,15 @@ "minLength": 32 } }, - "required": ["schemes", "credentials"], + "required": [ + "schemes", + "credentials" + ], "additionalProperties": false } }, - "required": ["url", "authentication"] + "required": [ + "url", + "authentication" + ] } diff --git a/dist/schemas/2.6.0/core/reporting-capabilities.json b/dist/schemas/2.6.0/core/reporting-capabilities.json index 87f4afb7fb..09e7a3a3a5 100644 --- a/dist/schemas/2.6.0/core/reporting-capabilities.json +++ b/dist/schemas/2.6.0/core/reporting-capabilities.json @@ -18,12 +18,21 @@ "type": "integer", "description": "Expected delay in minutes before reporting data becomes available (e.g., 240 for 4-hour delay)", "minimum": 0, - "examples": [240, 300, 1440] + "examples": [ + 240, + 300, + 1440 + ] }, "timezone": { "type": "string", "description": "Timezone for reporting periods. Use 'UTC' or IANA timezone (e.g., 'America/New_York'). Critical for daily/monthly frequency alignment.", - "examples": ["UTC", "America/New_York", "Europe/London", "America/Los_Angeles"] + "examples": [ + "UTC", + "America/New_York", + "Europe/London", + "America/Los_Angeles" + ] }, "supports_webhooks": { "type": "boolean", @@ -37,11 +46,26 @@ }, "uniqueItems": true, "examples": [ - ["impressions", "spend", "clicks", "video_completions"], - ["impressions", "spend", "conversions"] + [ + "impressions", + "spend", + "clicks", + "video_completions" + ], + [ + "impressions", + "spend", + "conversions" + ] ] } }, - "required": ["available_reporting_frequencies", "expected_delay_minutes", "timezone", "supports_webhooks", "available_metrics"], - "additionalProperties": false -} \ No newline at end of file + "required": [ + "available_reporting_frequencies", + "expected_delay_minutes", + "timezone", + "supports_webhooks", + "available_metrics" + ], + "additionalProperties": true +} diff --git a/dist/schemas/2.6.0/core/response.json b/dist/schemas/2.6.0/core/response.json index 86658df008..793d99e789 100644 --- a/dist/schemas/2.6.0/core/response.json +++ b/dist/schemas/2.6.0/core/response.json @@ -17,6 +17,8 @@ "description": "AdCP task-specific response data (see individual task response schemas)" } }, - "required": ["message"], - "additionalProperties": false -} \ No newline at end of file + "required": [ + "message" + ], + "additionalProperties": true +} diff --git a/dist/schemas/2.6.0/core/signal-filters.json b/dist/schemas/2.6.0/core/signal-filters.json index 00afa4c4e3..928eff4007 100644 --- a/dist/schemas/2.6.0/core/signal-filters.json +++ b/dist/schemas/2.6.0/core/signal-filters.json @@ -31,5 +31,5 @@ "maximum": 100 } }, - "additionalProperties": false + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/core/sub-asset.json b/dist/schemas/2.6.0/core/sub-asset.json index 276062d9b6..3b15939420 100644 --- a/dist/schemas/2.6.0/core/sub-asset.json +++ b/dist/schemas/2.6.0/core/sub-asset.json @@ -26,8 +26,13 @@ "description": "URL for media assets (images, videos, etc.)" } }, - "required": ["asset_kind", "asset_type", "asset_id", "content_uri"], - "additionalProperties": false + "required": [ + "asset_kind", + "asset_type", + "asset_id", + "content_uri" + ], + "additionalProperties": true }, { "type": "object", @@ -62,8 +67,13 @@ "description": "Text content for text-based assets like headlines, body text, CTA text, etc." } }, - "required": ["asset_kind", "asset_type", "asset_id", "content"], - "additionalProperties": false + "required": [ + "asset_kind", + "asset_type", + "asset_id", + "content" + ], + "additionalProperties": true } ] } diff --git a/dist/schemas/2.6.0/core/targeting.json b/dist/schemas/2.6.0/core/targeting.json index de1bf199dd..38e029bbad 100644 --- a/dist/schemas/2.6.0/core/targeting.json +++ b/dist/schemas/2.6.0/core/targeting.json @@ -46,5 +46,5 @@ "$ref": "/schemas/2.6.0/core/frequency-cap.json" } }, - "additionalProperties": false -} \ No newline at end of file + "additionalProperties": true +} diff --git a/dist/schemas/2.6.0/core/tasks-get-request.json b/dist/schemas/2.6.0/core/tasks-get-request.json index 5a8e754ae8..63a3dd2293 100644 --- a/dist/schemas/2.6.0/core/tasks-get-request.json +++ b/dist/schemas/2.6.0/core/tasks-get-request.json @@ -24,7 +24,7 @@ "required": [ "task_id" ], - "additionalProperties": false, + "additionalProperties": true, "examples": [ { "description": "Check task status", diff --git a/dist/schemas/2.6.0/core/tasks-get-response.json b/dist/schemas/2.6.0/core/tasks-get-response.json index 012f831e68..589628a570 100644 --- a/dist/schemas/2.6.0/core/tasks-get-response.json +++ b/dist/schemas/2.6.0/core/tasks-get-response.json @@ -69,7 +69,7 @@ "description": "Current step number" } }, - "additionalProperties": false + "additionalProperties": true }, "error": { "type": "object", @@ -112,7 +112,7 @@ "code", "message" ], - "additionalProperties": false + "additionalProperties": true }, "history": { "type": "array", @@ -144,7 +144,7 @@ "type", "data" ], - "additionalProperties": false + "additionalProperties": true } }, "context": { @@ -162,5 +162,5 @@ "created_at", "updated_at" ], - "additionalProperties": false + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/core/tasks-list-request.json b/dist/schemas/2.6.0/core/tasks-list-request.json index e2d8c5e60b..d073fb7d67 100644 --- a/dist/schemas/2.6.0/core/tasks-list-request.json +++ b/dist/schemas/2.6.0/core/tasks-list-request.json @@ -79,7 +79,7 @@ "description": "Filter tasks that have webhook configuration when true" } }, - "additionalProperties": false + "additionalProperties": true }, "sort": { "type": "object", @@ -103,7 +103,7 @@ "description": "Sort direction" } }, - "additionalProperties": false + "additionalProperties": true }, "pagination": { "type": "object", @@ -123,7 +123,7 @@ "description": "Number of tasks to skip" } }, - "additionalProperties": false + "additionalProperties": true }, "include_history": { "type": "boolean", @@ -137,7 +137,7 @@ "$ref": "/schemas/2.6.0/core/ext.json" } }, - "additionalProperties": false, + "additionalProperties": true, "examples": [ { "description": "List all pending tasks across domains", diff --git a/dist/schemas/2.6.0/core/tasks-list-response.json b/dist/schemas/2.6.0/core/tasks-list-response.json index 8d6770433a..b739a0e8c2 100644 --- a/dist/schemas/2.6.0/core/tasks-list-response.json +++ b/dist/schemas/2.6.0/core/tasks-list-response.json @@ -34,7 +34,7 @@ "description": "Number of signals tasks in results" } }, - "additionalProperties": false + "additionalProperties": true }, "status_breakdown": { "type": "object", @@ -70,14 +70,14 @@ "field", "direction" ], - "additionalProperties": false + "additionalProperties": true } }, "required": [ "total_matching", "returned" ], - "additionalProperties": false + "additionalProperties": true }, "tasks": { "type": "array", @@ -133,7 +133,7 @@ "created_at", "updated_at" ], - "additionalProperties": false + "additionalProperties": true } }, "pagination": { @@ -165,7 +165,7 @@ "offset", "has_more" ], - "additionalProperties": false + "additionalProperties": true }, "context": { "$ref": "/schemas/2.6.0/core/context.json" @@ -179,5 +179,5 @@ "tasks", "pagination" ], - "additionalProperties": false + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/creative/asset-types/index.json b/dist/schemas/2.6.0/creative/asset-types/index.json index d92d15944e..14a3531866 100644 --- a/dist/schemas/2.6.0/creative/asset-types/index.json +++ b/dist/schemas/2.6.0/creative/asset-types/index.json @@ -4,7 +4,7 @@ "title": "AdCP Asset Type Registry", "description": "Registry of asset types used in AdCP creative manifests. Each asset type defines the structure of actual content payloads (what you send), not requirements or constraints (which belong in format specifications).", "version": "1.0.0", - "lastUpdated": "2026-01-05", + "lastUpdated": "2026-01-07", "asset_types": { "image": { "description": "Static image asset (JPG, PNG, GIF, WebP, SVG)", @@ -99,5 +99,8 @@ "example_flow": "Format says 'hero_image' must be type 'image' with width 1200, height 627. Manifest provides hero_image: {url: '...', width: 1200, height: 627}. The format spec tells us it's an image type." }, "adcp_version": "2.6.0", - "baseUrl": "/schemas/2.6.0" + "baseUrl": "/schemas/2.6.0", + "versioning": { + "note": "AdCP uses build-time versioning. This directory contains schemas for AdCP 2.6.0. Full semantic versions are available at /schemas/{version}/ (e.g., /schemas/2.5.0/). Major version aliases point to the latest release: /schemas/v2/ → /schemas/2.6.0/." + } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/creative/list-creative-formats-request.json b/dist/schemas/2.6.0/creative/list-creative-formats-request.json index b59e05cf96..f6f55c48d8 100644 --- a/dist/schemas/2.6.0/creative/list-creative-formats-request.json +++ b/dist/schemas/2.6.0/creative/list-creative-formats-request.json @@ -69,5 +69,5 @@ "$ref": "/schemas/2.6.0/core/ext.json" } }, - "additionalProperties": false + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/creative/list-creative-formats-response.json b/dist/schemas/2.6.0/creative/list-creative-formats-response.json index 9d87b39bd3..628944be54 100644 --- a/dist/schemas/2.6.0/creative/list-creative-formats-response.json +++ b/dist/schemas/2.6.0/creative/list-creative-formats-response.json @@ -57,5 +57,5 @@ "required": [ "formats" ], - "additionalProperties": false + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/creative/preview-creative-request.json b/dist/schemas/2.6.0/creative/preview-creative-request.json index de8fa1dccb..803cbf16b2 100644 --- a/dist/schemas/2.6.0/creative/preview-creative-request.json +++ b/dist/schemas/2.6.0/creative/preview-creative-request.json @@ -33,7 +33,7 @@ }, "macros": { "type": "object", - "description": "Macro values to use for this preview. Supports all universal macros from the format's supported_macros list. See docs/media-buy/creatives/universal-macros.md for available macros.", + "description": "Macro values to use for this preview. Supports all universal macros from the format's supported_macros list. See docs/creative/universal-macros.md for available macros.", "additionalProperties": { "type": "string" } @@ -46,7 +46,7 @@ "required": [ "name" ], - "additionalProperties": false + "additionalProperties": true } }, "template_id": { @@ -70,7 +70,7 @@ "format_id", "creative_manifest" ], - "additionalProperties": false + "additionalProperties": true }, { "type": "object", @@ -120,7 +120,7 @@ "required": [ "name" ], - "additionalProperties": false + "additionalProperties": true } }, "template_id": { @@ -137,7 +137,7 @@ "format_id", "creative_manifest" ], - "additionalProperties": false + "additionalProperties": true }, "minItems": 1, "maxItems": 50 @@ -158,7 +158,7 @@ "request_type", "requests" ], - "additionalProperties": false + "additionalProperties": true } ] } diff --git a/dist/schemas/2.6.0/creative/preview-creative-response.json b/dist/schemas/2.6.0/creative/preview-creative-response.json index 9a24e445fe..4591e3a3f9 100644 --- a/dist/schemas/2.6.0/creative/preview-creative-response.json +++ b/dist/schemas/2.6.0/creative/preview-creative-response.json @@ -87,7 +87,7 @@ "previews", "expires_at" ], - "additionalProperties": false + "additionalProperties": true }, { "title": "PreviewCreativeBatchResponse", @@ -239,7 +239,7 @@ "response_type", "results" ], - "additionalProperties": false + "additionalProperties": true } ] } diff --git a/dist/schemas/2.6.0/creative/preview-render.json b/dist/schemas/2.6.0/creative/preview-render.json index 0fc66d72eb..dae9e43edd 100644 --- a/dist/schemas/2.6.0/creative/preview-render.json +++ b/dist/schemas/2.6.0/creative/preview-render.json @@ -39,7 +39,10 @@ "minimum": 0 } }, - "required": ["width", "height"] + "required": [ + "width", + "height" + ] }, "embedding": { "type": "object", @@ -64,8 +67,13 @@ } } }, - "required": ["render_id", "output_format", "preview_url", "role"], - "additionalProperties": false + "required": [ + "render_id", + "output_format", + "preview_url", + "role" + ], + "additionalProperties": true }, { "type": "object", @@ -101,7 +109,10 @@ "minimum": 0 } }, - "required": ["width", "height"] + "required": [ + "width", + "height" + ] }, "embedding": { "type": "object", @@ -126,8 +137,13 @@ } } }, - "required": ["render_id", "output_format", "preview_html", "role"], - "additionalProperties": false + "required": [ + "render_id", + "output_format", + "preview_html", + "role" + ], + "additionalProperties": true }, { "type": "object", @@ -168,7 +184,10 @@ "minimum": 0 } }, - "required": ["width", "height"] + "required": [ + "width", + "height" + ] }, "embedding": { "type": "object", @@ -193,8 +212,14 @@ } } }, - "required": ["render_id", "output_format", "preview_url", "preview_html", "role"], - "additionalProperties": false + "required": [ + "render_id", + "output_format", + "preview_url", + "preview_html", + "role" + ], + "additionalProperties": true } ] } diff --git a/dist/schemas/2.6.0/enums/adcp-domain.json b/dist/schemas/2.6.0/enums/adcp-domain.json index 515fed77f1..2d48f76e84 100644 --- a/dist/schemas/2.6.0/enums/adcp-domain.json +++ b/dist/schemas/2.6.0/enums/adcp-domain.json @@ -4,5 +4,8 @@ "title": "AdCP Domain", "description": "AdCP protocol domains for task categorization", "type": "string", - "enum": ["media-buy", "signals"] + "enum": [ + "media-buy", + "signals" + ] } diff --git a/dist/schemas/2.6.0/enums/auth-scheme.json b/dist/schemas/2.6.0/enums/auth-scheme.json index 9e53c32112..71feb29afa 100644 --- a/dist/schemas/2.6.0/enums/auth-scheme.json +++ b/dist/schemas/2.6.0/enums/auth-scheme.json @@ -4,5 +4,8 @@ "title": "Authentication Scheme", "description": "Authentication schemes for push notification endpoints", "type": "string", - "enum": ["Bearer", "HMAC-SHA256"] + "enum": [ + "Bearer", + "HMAC-SHA256" + ] } diff --git a/dist/schemas/2.6.0/enums/co-branding-requirement.json b/dist/schemas/2.6.0/enums/co-branding-requirement.json index 5375e6093c..7d363a36fc 100644 --- a/dist/schemas/2.6.0/enums/co-branding-requirement.json +++ b/dist/schemas/2.6.0/enums/co-branding-requirement.json @@ -4,5 +4,9 @@ "title": "Co-Branding Requirement", "description": "Co-branding policy for creatives (retailer/publisher brand inclusion)", "type": "string", - "enum": ["required", "optional", "none"] + "enum": [ + "required", + "optional", + "none" + ] } diff --git a/dist/schemas/2.6.0/enums/creative-action.json b/dist/schemas/2.6.0/enums/creative-action.json index afa0dbb510..a1a74c0953 100644 --- a/dist/schemas/2.6.0/enums/creative-action.json +++ b/dist/schemas/2.6.0/enums/creative-action.json @@ -4,5 +4,11 @@ "title": "Creative Action", "description": "Action taken on a creative during sync operation", "type": "string", - "enum": ["created", "updated", "unchanged", "failed", "deleted"] + "enum": [ + "created", + "updated", + "unchanged", + "failed", + "deleted" + ] } diff --git a/dist/schemas/2.6.0/enums/creative-agent-capability.json b/dist/schemas/2.6.0/enums/creative-agent-capability.json index ad9c08555c..d7a47923e6 100644 --- a/dist/schemas/2.6.0/enums/creative-agent-capability.json +++ b/dist/schemas/2.6.0/enums/creative-agent-capability.json @@ -4,5 +4,10 @@ "title": "Creative Agent Capability", "description": "Capabilities supported by creative agents for format handling", "type": "string", - "enum": ["validation", "assembly", "generation", "preview"] + "enum": [ + "validation", + "assembly", + "generation", + "preview" + ] } diff --git a/dist/schemas/2.6.0/enums/creative-status.json b/dist/schemas/2.6.0/enums/creative-status.json index a2010e240e..acaead85ec 100644 --- a/dist/schemas/2.6.0/enums/creative-status.json +++ b/dist/schemas/2.6.0/enums/creative-status.json @@ -4,11 +4,16 @@ "title": "Creative Status", "description": "Status of a creative asset", "type": "string", - "enum": ["processing", "approved", "rejected", "pending_review"], + "enum": [ + "processing", + "approved", + "rejected", + "pending_review" + ], "enumDescriptions": { "processing": "Creative is being processed or transcoded", "approved": "Creative has been approved and is ready for delivery", "rejected": "Creative has been rejected due to policy or technical issues", "pending_review": "Creative is under review" } -} \ No newline at end of file +} diff --git a/dist/schemas/2.6.0/enums/daast-version.json b/dist/schemas/2.6.0/enums/daast-version.json index 4be2d3589a..c2229db626 100644 --- a/dist/schemas/2.6.0/enums/daast-version.json +++ b/dist/schemas/2.6.0/enums/daast-version.json @@ -4,5 +4,8 @@ "title": "DAAST Version", "description": "Supported DAAST (Digital Audio Ad Serving Template) specification versions", "type": "string", - "enum": ["1.0", "1.1"] + "enum": [ + "1.0", + "1.1" + ] } diff --git a/dist/schemas/2.6.0/enums/delivery-type.json b/dist/schemas/2.6.0/enums/delivery-type.json index 1ae5167f22..30c0d2d1f8 100644 --- a/dist/schemas/2.6.0/enums/delivery-type.json +++ b/dist/schemas/2.6.0/enums/delivery-type.json @@ -4,9 +4,12 @@ "title": "Delivery Type", "description": "Type of inventory delivery", "type": "string", - "enum": ["guaranteed", "non_guaranteed"], + "enum": [ + "guaranteed", + "non_guaranteed" + ], "enumDescriptions": { "guaranteed": "Reserved inventory with guaranteed delivery", "non_guaranteed": "Auction-based inventory without delivery guarantees" } -} \ No newline at end of file +} diff --git a/dist/schemas/2.6.0/enums/dimension-unit.json b/dist/schemas/2.6.0/enums/dimension-unit.json index ee64a64f0b..fb914e344a 100644 --- a/dist/schemas/2.6.0/enums/dimension-unit.json +++ b/dist/schemas/2.6.0/enums/dimension-unit.json @@ -4,5 +4,10 @@ "title": "Dimension Unit", "description": "Units of measurement for creative format dimensions", "type": "string", - "enum": ["px", "dp", "inches", "cm"] + "enum": [ + "px", + "dp", + "inches", + "cm" + ] } diff --git a/dist/schemas/2.6.0/enums/feed-format.json b/dist/schemas/2.6.0/enums/feed-format.json index 9b2af3263d..7e1d2f4551 100644 --- a/dist/schemas/2.6.0/enums/feed-format.json +++ b/dist/schemas/2.6.0/enums/feed-format.json @@ -4,5 +4,9 @@ "title": "Feed Format", "description": "Product catalog feed format types", "type": "string", - "enum": ["google_merchant_center", "facebook_catalog", "custom"] + "enum": [ + "google_merchant_center", + "facebook_catalog", + "custom" + ] } diff --git a/dist/schemas/2.6.0/enums/format-id-parameter.json b/dist/schemas/2.6.0/enums/format-id-parameter.json index 85652e0562..724eb1a3f3 100644 --- a/dist/schemas/2.6.0/enums/format-id-parameter.json +++ b/dist/schemas/2.6.0/enums/format-id-parameter.json @@ -4,5 +4,8 @@ "title": "Format ID Parameter", "description": "Types of parameters that template formats accept in format_id objects to create parameterized format identifiers", "type": "string", - "enum": ["dimensions", "duration"] + "enum": [ + "dimensions", + "duration" + ] } diff --git a/dist/schemas/2.6.0/enums/frequency-cap-scope.json b/dist/schemas/2.6.0/enums/frequency-cap-scope.json index 149d37f822..739461d547 100644 --- a/dist/schemas/2.6.0/enums/frequency-cap-scope.json +++ b/dist/schemas/2.6.0/enums/frequency-cap-scope.json @@ -4,8 +4,10 @@ "title": "Frequency Cap Scope", "description": "Scope for frequency cap application", "type": "string", - "enum": ["package"], + "enum": [ + "package" + ], "enumDescriptions": { "package": "Apply frequency cap at the package level" } -} \ No newline at end of file +} diff --git a/dist/schemas/2.6.0/enums/history-entry-type.json b/dist/schemas/2.6.0/enums/history-entry-type.json index bfb82dea88..e1fdc6f054 100644 --- a/dist/schemas/2.6.0/enums/history-entry-type.json +++ b/dist/schemas/2.6.0/enums/history-entry-type.json @@ -4,5 +4,8 @@ "title": "History Entry Type", "description": "Type of entry in task execution history", "type": "string", - "enum": ["request", "response"] + "enum": [ + "request", + "response" + ] } diff --git a/dist/schemas/2.6.0/enums/http-method.json b/dist/schemas/2.6.0/enums/http-method.json index 290117fbaf..caeccbae98 100644 --- a/dist/schemas/2.6.0/enums/http-method.json +++ b/dist/schemas/2.6.0/enums/http-method.json @@ -4,5 +4,8 @@ "title": "HTTP Method", "description": "HTTP methods supported for webhook requests", "type": "string", - "enum": ["GET", "POST"] + "enum": [ + "GET", + "POST" + ] } diff --git a/dist/schemas/2.6.0/enums/identifier-types.json b/dist/schemas/2.6.0/enums/identifier-types.json index e744a2534f..c7f65f3ecd 100644 --- a/dist/schemas/2.6.0/enums/identifier-types.json +++ b/dist/schemas/2.6.0/enums/identifier-types.json @@ -6,7 +6,7 @@ "type": "string", "enum": [ "domain", - "subdomain", + "subdomain", "network_id", "ios_bundle", "android_package", @@ -27,8 +27,8 @@ ], "examples": [ "domain", - "ios_bundle", + "ios_bundle", "venue_id", "apple_podcast_id" ] -} \ No newline at end of file +} diff --git a/dist/schemas/2.6.0/enums/javascript-module-type.json b/dist/schemas/2.6.0/enums/javascript-module-type.json index a0790e6856..d53b8cf59c 100644 --- a/dist/schemas/2.6.0/enums/javascript-module-type.json +++ b/dist/schemas/2.6.0/enums/javascript-module-type.json @@ -4,5 +4,9 @@ "title": "JavaScript Module Type", "description": "JavaScript module format types for creative assets", "type": "string", - "enum": ["esm", "commonjs", "script"] + "enum": [ + "esm", + "commonjs", + "script" + ] } diff --git a/dist/schemas/2.6.0/enums/landing-page-requirement.json b/dist/schemas/2.6.0/enums/landing-page-requirement.json index b80e591900..84bb74b9f4 100644 --- a/dist/schemas/2.6.0/enums/landing-page-requirement.json +++ b/dist/schemas/2.6.0/enums/landing-page-requirement.json @@ -4,5 +4,9 @@ "title": "Landing Page Requirement", "description": "Landing page policy for creative click-through destinations", "type": "string", - "enum": ["any", "retailer_site_only", "must_include_retailer"] + "enum": [ + "any", + "retailer_site_only", + "must_include_retailer" + ] } diff --git a/dist/schemas/2.6.0/enums/markdown-flavor.json b/dist/schemas/2.6.0/enums/markdown-flavor.json index 6195171dd6..1d9a1fa265 100644 --- a/dist/schemas/2.6.0/enums/markdown-flavor.json +++ b/dist/schemas/2.6.0/enums/markdown-flavor.json @@ -4,5 +4,8 @@ "title": "Markdown Flavor", "description": "Markdown specification flavors supported for text assets", "type": "string", - "enum": ["commonmark", "gfm"] + "enum": [ + "commonmark", + "gfm" + ] } diff --git a/dist/schemas/2.6.0/enums/media-buy-status.json b/dist/schemas/2.6.0/enums/media-buy-status.json index 0c8ff74923..3b09ad8a94 100644 --- a/dist/schemas/2.6.0/enums/media-buy-status.json +++ b/dist/schemas/2.6.0/enums/media-buy-status.json @@ -4,11 +4,16 @@ "title": "Media Buy Status", "description": "Status of a media buy", "type": "string", - "enum": ["pending_activation", "active", "paused", "completed"], + "enum": [ + "pending_activation", + "active", + "paused", + "completed" + ], "enumDescriptions": { "pending_activation": "Media buy created but not yet activated", "active": "Media buy is currently running", "paused": "Media buy is temporarily paused", "completed": "Media buy has finished running" } -} \ No newline at end of file +} diff --git a/dist/schemas/2.6.0/enums/notification-type.json b/dist/schemas/2.6.0/enums/notification-type.json index 3ebec716b8..466418fd35 100644 --- a/dist/schemas/2.6.0/enums/notification-type.json +++ b/dist/schemas/2.6.0/enums/notification-type.json @@ -4,5 +4,10 @@ "title": "Notification Type", "description": "Type of delivery notification for media buy reporting", "type": "string", - "enum": ["scheduled", "final", "delayed", "adjusted"] + "enum": [ + "scheduled", + "final", + "delayed", + "adjusted" + ] } diff --git a/dist/schemas/2.6.0/enums/pacing.json b/dist/schemas/2.6.0/enums/pacing.json index 86e8c6a0a5..7028b5a850 100644 --- a/dist/schemas/2.6.0/enums/pacing.json +++ b/dist/schemas/2.6.0/enums/pacing.json @@ -4,10 +4,14 @@ "title": "Pacing", "description": "Budget pacing strategy", "type": "string", - "enum": ["even", "asap", "front_loaded"], + "enum": [ + "even", + "asap", + "front_loaded" + ], "enumDescriptions": { "even": "Allocate remaining budget evenly over remaining campaign duration (default)", "asap": "Spend remaining budget as quickly as possible", "front_loaded": "Allocate more remaining budget earlier in the remaining campaign period" } -} \ No newline at end of file +} diff --git a/dist/schemas/2.6.0/enums/preview-output-format.json b/dist/schemas/2.6.0/enums/preview-output-format.json index 6d090e0fcf..896ef82afa 100644 --- a/dist/schemas/2.6.0/enums/preview-output-format.json +++ b/dist/schemas/2.6.0/enums/preview-output-format.json @@ -4,5 +4,8 @@ "title": "Preview Output Format", "description": "Output format for creative previews", "type": "string", - "enum": ["url", "html"] + "enum": [ + "url", + "html" + ] } diff --git a/dist/schemas/2.6.0/enums/reporting-frequency.json b/dist/schemas/2.6.0/enums/reporting-frequency.json index 6b1b5b80b4..d55f2eeb41 100644 --- a/dist/schemas/2.6.0/enums/reporting-frequency.json +++ b/dist/schemas/2.6.0/enums/reporting-frequency.json @@ -4,5 +4,9 @@ "title": "Reporting Frequency", "description": "Available frequencies for delivery reports and metrics updates", "type": "string", - "enum": ["hourly", "daily", "monthly"] + "enum": [ + "hourly", + "daily", + "monthly" + ] } diff --git a/dist/schemas/2.6.0/enums/signal-catalog-type.json b/dist/schemas/2.6.0/enums/signal-catalog-type.json index cb30a52d5b..bce70e89a9 100644 --- a/dist/schemas/2.6.0/enums/signal-catalog-type.json +++ b/dist/schemas/2.6.0/enums/signal-catalog-type.json @@ -4,5 +4,9 @@ "title": "Signal Catalog Type", "description": "Types of signal catalogs available for audience targeting", "type": "string", - "enum": ["marketplace", "custom", "owned"] + "enum": [ + "marketplace", + "custom", + "owned" + ] } diff --git a/dist/schemas/2.6.0/enums/sort-direction.json b/dist/schemas/2.6.0/enums/sort-direction.json index c88e53fe20..884b5c4f50 100644 --- a/dist/schemas/2.6.0/enums/sort-direction.json +++ b/dist/schemas/2.6.0/enums/sort-direction.json @@ -4,5 +4,8 @@ "title": "Sort Direction", "description": "Sort direction for list queries", "type": "string", - "enum": ["asc", "desc"] + "enum": [ + "asc", + "desc" + ] } diff --git a/dist/schemas/2.6.0/enums/standard-format-ids.json b/dist/schemas/2.6.0/enums/standard-format-ids.json index 8ca9047467..0b59c055d9 100644 --- a/dist/schemas/2.6.0/enums/standard-format-ids.json +++ b/dist/schemas/2.6.0/enums/standard-format-ids.json @@ -100,4 +100,4 @@ "dynamic_creative_formats": [ "display_dynamic_300x250" ] -} \ No newline at end of file +} diff --git a/dist/schemas/2.6.0/enums/task-status.json b/dist/schemas/2.6.0/enums/task-status.json index 7095a972c7..d2c5c138c3 100644 --- a/dist/schemas/2.6.0/enums/task-status.json +++ b/dist/schemas/2.6.0/enums/task-status.json @@ -6,12 +6,12 @@ "type": "string", "enum": [ "submitted", - "working", + "working", "input-required", "completed", "canceled", "failed", - "rejected", + "rejected", "auth-required", "unknown" ], @@ -26,4 +26,4 @@ "auth-required": "Task requires authentication to proceed", "unknown": "Task is in an unknown or indeterminate state" } -} \ No newline at end of file +} diff --git a/dist/schemas/2.6.0/enums/update-frequency.json b/dist/schemas/2.6.0/enums/update-frequency.json index 6a14b8124e..82bd2f967c 100644 --- a/dist/schemas/2.6.0/enums/update-frequency.json +++ b/dist/schemas/2.6.0/enums/update-frequency.json @@ -4,5 +4,10 @@ "title": "Update Frequency", "description": "Frequency of product catalog updates", "type": "string", - "enum": ["realtime", "hourly", "daily", "weekly"] + "enum": [ + "realtime", + "hourly", + "daily", + "weekly" + ] } diff --git a/dist/schemas/2.6.0/enums/url-asset-type.json b/dist/schemas/2.6.0/enums/url-asset-type.json index 5866c5a627..7169df42cd 100644 --- a/dist/schemas/2.6.0/enums/url-asset-type.json +++ b/dist/schemas/2.6.0/enums/url-asset-type.json @@ -4,5 +4,9 @@ "title": "URL Asset Type", "description": "Types of URL assets for tracking and click-through purposes", "type": "string", - "enum": ["clickthrough", "tracker_pixel", "tracker_script"] + "enum": [ + "clickthrough", + "tracker_pixel", + "tracker_script" + ] } diff --git a/dist/schemas/2.6.0/enums/validation-mode.json b/dist/schemas/2.6.0/enums/validation-mode.json index ad22bb60a4..c27c0cce57 100644 --- a/dist/schemas/2.6.0/enums/validation-mode.json +++ b/dist/schemas/2.6.0/enums/validation-mode.json @@ -4,5 +4,8 @@ "title": "Validation Mode", "description": "Creative validation strictness levels", "type": "string", - "enum": ["strict", "lenient"] + "enum": [ + "strict", + "lenient" + ] } diff --git a/dist/schemas/2.6.0/enums/vast-version.json b/dist/schemas/2.6.0/enums/vast-version.json index ecc5a669c1..fe3c48b8c7 100644 --- a/dist/schemas/2.6.0/enums/vast-version.json +++ b/dist/schemas/2.6.0/enums/vast-version.json @@ -4,5 +4,11 @@ "title": "VAST Version", "description": "Supported VAST (Video Ad Serving Template) specification versions", "type": "string", - "enum": ["2.0", "3.0", "4.0", "4.1", "4.2"] + "enum": [ + "2.0", + "3.0", + "4.0", + "4.1", + "4.2" + ] } diff --git a/dist/schemas/2.6.0/enums/webhook-response-type.json b/dist/schemas/2.6.0/enums/webhook-response-type.json index ae75b3696f..e0423fbb6b 100644 --- a/dist/schemas/2.6.0/enums/webhook-response-type.json +++ b/dist/schemas/2.6.0/enums/webhook-response-type.json @@ -4,5 +4,10 @@ "title": "Webhook Response Type", "description": "Expected response content type from webhook endpoints", "type": "string", - "enum": ["html", "json", "xml", "javascript"] + "enum": [ + "html", + "json", + "xml", + "javascript" + ] } diff --git a/dist/schemas/2.6.0/enums/webhook-security-method.json b/dist/schemas/2.6.0/enums/webhook-security-method.json index ea5df0e0d3..61f23eb2a4 100644 --- a/dist/schemas/2.6.0/enums/webhook-security-method.json +++ b/dist/schemas/2.6.0/enums/webhook-security-method.json @@ -4,5 +4,9 @@ "title": "Webhook Security Method", "description": "Security methods for authenticating webhook requests", "type": "string", - "enum": ["hmac_sha256", "api_key", "none"] + "enum": [ + "hmac_sha256", + "api_key", + "none" + ] } diff --git a/dist/schemas/2.6.0/index.json b/dist/schemas/2.6.0/index.json index 169089e4a9..ecb888befd 100644 --- a/dist/schemas/2.6.0/index.json +++ b/dist/schemas/2.6.0/index.json @@ -7,7 +7,7 @@ "adcp_version": "2.6.0", "standard_formats_version": "2.0.0", "versioning": { - "note": "AdCP uses path-based versioning. The schema URL path (/schemas/) indicates the version. Individual request/response schemas do NOT include adcp_version fields. Compatibility follows semantic versioning rules." + "note": "AdCP uses build-time versioning. This directory contains schemas for AdCP 2.6.0. Full semantic versions are available at /schemas/{version}/ (e.g., /schemas/2.5.0/). Major version aliases point to the latest release: /schemas/v2/ → /schemas/2.6.0/." }, "changelog": { "2.0.0": { @@ -31,7 +31,7 @@ ] } }, - "lastUpdated": "2026-01-05", + "lastUpdated": "2026-01-07", "baseUrl": "/schemas/2.6.0", "schemas": { "core": { diff --git a/dist/schemas/2.6.0/media-buy/build-creative-request.json b/dist/schemas/2.6.0/media-buy/build-creative-request.json index 27abfef9b0..a14b3c7a4d 100644 --- a/dist/schemas/2.6.0/media-buy/build-creative-request.json +++ b/dist/schemas/2.6.0/media-buy/build-creative-request.json @@ -27,5 +27,5 @@ "required": [ "target_format_id" ], - "additionalProperties": false + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/media-buy/build-creative-response.json b/dist/schemas/2.6.0/media-buy/build-creative-response.json index 8457ce4843..7cf9bdf53f 100644 --- a/dist/schemas/2.6.0/media-buy/build-creative-response.json +++ b/dist/schemas/2.6.0/media-buy/build-creative-response.json @@ -24,7 +24,7 @@ "required": [ "creative_manifest" ], - "additionalProperties": false, + "additionalProperties": true, "not": { "required": [ "errors" @@ -54,7 +54,7 @@ "required": [ "errors" ], - "additionalProperties": false, + "additionalProperties": true, "not": { "required": [ "creative_manifest" diff --git a/dist/schemas/2.6.0/media-buy/create-media-buy-async-response-input-required.json b/dist/schemas/2.6.0/media-buy/create-media-buy-async-response-input-required.json index 5b9127414a..da9db3b3f6 100644 --- a/dist/schemas/2.6.0/media-buy/create-media-buy-async-response-input-required.json +++ b/dist/schemas/2.6.0/media-buy/create-media-buy-async-response-input-required.json @@ -27,5 +27,5 @@ "$ref": "/schemas/2.6.0/core/ext.json" } }, - "additionalProperties": false + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/media-buy/create-media-buy-async-response-submitted.json b/dist/schemas/2.6.0/media-buy/create-media-buy-async-response-submitted.json index 92eed288e4..c69678834d 100644 --- a/dist/schemas/2.6.0/media-buy/create-media-buy-async-response-submitted.json +++ b/dist/schemas/2.6.0/media-buy/create-media-buy-async-response-submitted.json @@ -12,6 +12,5 @@ "$ref": "/schemas/2.6.0/core/ext.json" } }, - "additionalProperties": false + "additionalProperties": true } - diff --git a/dist/schemas/2.6.0/media-buy/create-media-buy-async-response-working.json b/dist/schemas/2.6.0/media-buy/create-media-buy-async-response-working.json index 2b332a7162..32c6ad1692 100644 --- a/dist/schemas/2.6.0/media-buy/create-media-buy-async-response-working.json +++ b/dist/schemas/2.6.0/media-buy/create-media-buy-async-response-working.json @@ -32,6 +32,5 @@ "$ref": "/schemas/2.6.0/core/ext.json" } }, - "additionalProperties": false + "additionalProperties": true } - diff --git a/dist/schemas/2.6.0/media-buy/create-media-buy-request.json b/dist/schemas/2.6.0/media-buy/create-media-buy-request.json index d7b023d5b3..38ea017ddd 100644 --- a/dist/schemas/2.6.0/media-buy/create-media-buy-request.json +++ b/dist/schemas/2.6.0/media-buy/create-media-buy-request.json @@ -66,7 +66,10 @@ "minLength": 32 } }, - "required": ["schemes", "credentials"], + "required": [ + "schemes", + "credentials" + ], "additionalProperties": false }, "reporting_frequency": { @@ -98,8 +101,12 @@ "uniqueItems": true } }, - "required": ["url", "authentication", "reporting_frequency"], - "additionalProperties": false + "required": [ + "url", + "authentication", + "reporting_frequency" + ], + "additionalProperties": true }, "context": { "$ref": "/schemas/2.6.0/core/context.json" @@ -115,5 +122,5 @@ "start_time", "end_time" ], - "additionalProperties": false + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/media-buy/create-media-buy-response.json b/dist/schemas/2.6.0/media-buy/create-media-buy-response.json index 3e799bf5c0..75bc8a63dc 100644 --- a/dist/schemas/2.6.0/media-buy/create-media-buy-response.json +++ b/dist/schemas/2.6.0/media-buy/create-media-buy-response.json @@ -42,7 +42,7 @@ "buyer_ref", "packages" ], - "additionalProperties": false, + "additionalProperties": true, "not": { "required": [ "errors" @@ -72,7 +72,7 @@ "required": [ "errors" ], - "additionalProperties": false, + "additionalProperties": true, "not": { "anyOf": [ { diff --git a/dist/schemas/2.6.0/media-buy/get-media-buy-delivery-request.json b/dist/schemas/2.6.0/media-buy/get-media-buy-delivery-request.json index d5d489ab15..74e834e676 100644 --- a/dist/schemas/2.6.0/media-buy/get-media-buy-delivery-request.json +++ b/dist/schemas/2.6.0/media-buy/get-media-buy-delivery-request.json @@ -50,5 +50,5 @@ "$ref": "/schemas/2.6.0/core/ext.json" } }, - "additionalProperties": false + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/media-buy/get-media-buy-delivery-response.json b/dist/schemas/2.6.0/media-buy/get-media-buy-delivery-response.json index 3c9f11e0ff..df29e40738 100644 --- a/dist/schemas/2.6.0/media-buy/get-media-buy-delivery-response.json +++ b/dist/schemas/2.6.0/media-buy/get-media-buy-delivery-response.json @@ -53,7 +53,7 @@ "start", "end" ], - "additionalProperties": false + "additionalProperties": true }, "currency": { "type": "string", @@ -95,7 +95,7 @@ "spend", "media_buy_count" ], - "additionalProperties": false + "additionalProperties": true }, "media_buy_deliveries": { "type": "array", @@ -249,7 +249,7 @@ "impressions", "spend" ], - "additionalProperties": false + "additionalProperties": true } } }, @@ -259,7 +259,7 @@ "totals", "by_package" ], - "additionalProperties": false + "additionalProperties": true } }, "errors": { @@ -281,5 +281,5 @@ "currency", "media_buy_deliveries" ], - "additionalProperties": false + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/media-buy/get-products-async-response-input-required.json b/dist/schemas/2.6.0/media-buy/get-products-async-response-input-required.json index 3b00b220ce..ff47e7cf88 100644 --- a/dist/schemas/2.6.0/media-buy/get-products-async-response-input-required.json +++ b/dist/schemas/2.6.0/media-buy/get-products-async-response-input-required.json @@ -34,6 +34,5 @@ "$ref": "/schemas/2.6.0/core/ext.json" } }, - "additionalProperties": false + "additionalProperties": true } - diff --git a/dist/schemas/2.6.0/media-buy/get-products-async-response-submitted.json b/dist/schemas/2.6.0/media-buy/get-products-async-response-submitted.json index ab5b818ab3..34d610a6c5 100644 --- a/dist/schemas/2.6.0/media-buy/get-products-async-response-submitted.json +++ b/dist/schemas/2.6.0/media-buy/get-products-async-response-submitted.json @@ -17,6 +17,5 @@ "$ref": "/schemas/2.6.0/core/ext.json" } }, - "additionalProperties": false + "additionalProperties": true } - diff --git a/dist/schemas/2.6.0/media-buy/get-products-async-response-working.json b/dist/schemas/2.6.0/media-buy/get-products-async-response-working.json index 8379996650..4adf970054 100644 --- a/dist/schemas/2.6.0/media-buy/get-products-async-response-working.json +++ b/dist/schemas/2.6.0/media-buy/get-products-async-response-working.json @@ -30,6 +30,5 @@ "$ref": "/schemas/2.6.0/core/ext.json" } }, - "additionalProperties": false + "additionalProperties": true } - diff --git a/dist/schemas/2.6.0/media-buy/get-products-request.json b/dist/schemas/2.6.0/media-buy/get-products-request.json index 05409ea608..b44dfabdbe 100644 --- a/dist/schemas/2.6.0/media-buy/get-products-request.json +++ b/dist/schemas/2.6.0/media-buy/get-products-request.json @@ -24,5 +24,5 @@ } }, "required": [], - "additionalProperties": false + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/media-buy/get-products-response.json b/dist/schemas/2.6.0/media-buy/get-products-response.json index ad86771aab..7212c9b4db 100644 --- a/dist/schemas/2.6.0/media-buy/get-products-response.json +++ b/dist/schemas/2.6.0/media-buy/get-products-response.json @@ -29,5 +29,5 @@ "required": [ "products" ], - "additionalProperties": false + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/media-buy/list-authorized-properties-request.json b/dist/schemas/2.6.0/media-buy/list-authorized-properties-request.json index 12527ac715..ced98a32bf 100644 --- a/dist/schemas/2.6.0/media-buy/list-authorized-properties-request.json +++ b/dist/schemas/2.6.0/media-buy/list-authorized-properties-request.json @@ -22,5 +22,5 @@ "$ref": "/schemas/2.6.0/core/ext.json" } }, - "additionalProperties": false + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/media-buy/list-authorized-properties-response.json b/dist/schemas/2.6.0/media-buy/list-authorized-properties-response.json index 755197622c..1c1101324a 100644 --- a/dist/schemas/2.6.0/media-buy/list-authorized-properties-response.json +++ b/dist/schemas/2.6.0/media-buy/list-authorized-properties-response.json @@ -66,5 +66,5 @@ "required": [ "publisher_domains" ], - "additionalProperties": false + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/media-buy/list-creative-formats-request.json b/dist/schemas/2.6.0/media-buy/list-creative-formats-request.json index 74a3e77143..c0a7c4b7b3 100644 --- a/dist/schemas/2.6.0/media-buy/list-creative-formats-request.json +++ b/dist/schemas/2.6.0/media-buy/list-creative-formats-request.json @@ -54,5 +54,5 @@ "$ref": "/schemas/2.6.0/core/ext.json" } }, - "additionalProperties": false + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/media-buy/list-creative-formats-response.json b/dist/schemas/2.6.0/media-buy/list-creative-formats-response.json index d80d679c19..30641c06b2 100644 --- a/dist/schemas/2.6.0/media-buy/list-creative-formats-response.json +++ b/dist/schemas/2.6.0/media-buy/list-creative-formats-response.json @@ -57,5 +57,5 @@ "required": [ "formats" ], - "additionalProperties": false + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/media-buy/list-creatives-request.json b/dist/schemas/2.6.0/media-buy/list-creatives-request.json index 17e0bd5674..b96c9fa9a1 100644 --- a/dist/schemas/2.6.0/media-buy/list-creatives-request.json +++ b/dist/schemas/2.6.0/media-buy/list-creatives-request.json @@ -23,7 +23,7 @@ "description": "Sort direction" } }, - "additionalProperties": false + "additionalProperties": true }, "pagination": { "type": "object", @@ -43,7 +43,7 @@ "description": "Number of creatives to skip" } }, - "additionalProperties": false + "additionalProperties": true }, "include_assignments": { "type": "boolean", @@ -86,7 +86,7 @@ "$ref": "/schemas/2.6.0/core/ext.json" } }, - "additionalProperties": false, + "additionalProperties": true, "examples": [ { "description": "List all approved video creatives", diff --git a/dist/schemas/2.6.0/media-buy/list-creatives-response.json b/dist/schemas/2.6.0/media-buy/list-creatives-response.json index 600796b6a9..99a9a73837 100644 --- a/dist/schemas/2.6.0/media-buy/list-creatives-response.json +++ b/dist/schemas/2.6.0/media-buy/list-creatives-response.json @@ -43,7 +43,7 @@ "total_matching", "returned" ], - "additionalProperties": false + "additionalProperties": true }, "pagination": { "type": "object", @@ -79,7 +79,7 @@ "offset", "has_more" ], - "additionalProperties": false + "additionalProperties": true }, "creatives": { "type": "array", @@ -206,14 +206,14 @@ "assigned_date", "status" ], - "additionalProperties": false + "additionalProperties": true } } }, "required": [ "assignment_count" ], - "additionalProperties": false + "additionalProperties": true }, "performance": { "type": "object", @@ -256,7 +256,7 @@ "required": [ "last_updated" ], - "additionalProperties": false + "additionalProperties": true }, "sub_assets": { "type": "array", @@ -274,7 +274,7 @@ "created_date", "updated_date" ], - "additionalProperties": false + "additionalProperties": true } }, "format_summary": { @@ -287,7 +287,7 @@ "minimum": 0 } }, - "additionalProperties": false + "additionalProperties": true }, "status_summary": { "type": "object", @@ -314,7 +314,7 @@ "minimum": 0 } }, - "additionalProperties": false + "additionalProperties": true }, "context": { "$ref": "/schemas/2.6.0/core/context.json" @@ -328,7 +328,7 @@ "pagination", "creatives" ], - "additionalProperties": false, + "additionalProperties": true, "examples": [ { "description": "Successful library query with results", diff --git a/dist/schemas/2.6.0/media-buy/package-request.json b/dist/schemas/2.6.0/media-buy/package-request.json index 2f424ddcf6..785ccc02f9 100644 --- a/dist/schemas/2.6.0/media-buy/package-request.json +++ b/dist/schemas/2.6.0/media-buy/package-request.json @@ -66,5 +66,5 @@ "budget", "pricing_option_id" ], - "additionalProperties": false + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/media-buy/provide-performance-feedback-request.json b/dist/schemas/2.6.0/media-buy/provide-performance-feedback-request.json index 93410c3068..a40f25c9f7 100644 --- a/dist/schemas/2.6.0/media-buy/provide-performance-feedback-request.json +++ b/dist/schemas/2.6.0/media-buy/provide-performance-feedback-request.json @@ -34,7 +34,7 @@ "start", "end" ], - "additionalProperties": false + "additionalProperties": true }, "performance_index": { "type": "number", @@ -84,5 +84,5 @@ ] } ], - "additionalProperties": false + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/media-buy/provide-performance-feedback-response.json b/dist/schemas/2.6.0/media-buy/provide-performance-feedback-response.json index fb1a1c3210..13db97f1bb 100644 --- a/dist/schemas/2.6.0/media-buy/provide-performance-feedback-response.json +++ b/dist/schemas/2.6.0/media-buy/provide-performance-feedback-response.json @@ -25,7 +25,7 @@ "required": [ "success" ], - "additionalProperties": false, + "additionalProperties": true, "not": { "required": [ "errors" @@ -55,7 +55,7 @@ "required": [ "errors" ], - "additionalProperties": false, + "additionalProperties": true, "not": { "required": [ "success" diff --git a/dist/schemas/2.6.0/media-buy/sync-creatives-async-response-input-required.json b/dist/schemas/2.6.0/media-buy/sync-creatives-async-response-input-required.json index 0e9078156d..27afb16e59 100644 --- a/dist/schemas/2.6.0/media-buy/sync-creatives-async-response-input-required.json +++ b/dist/schemas/2.6.0/media-buy/sync-creatives-async-response-input-required.json @@ -21,5 +21,5 @@ "$ref": "/schemas/2.6.0/core/ext.json" } }, - "additionalProperties": false + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/media-buy/sync-creatives-async-response-submitted.json b/dist/schemas/2.6.0/media-buy/sync-creatives-async-response-submitted.json index dd8d802b4b..c891b92780 100644 --- a/dist/schemas/2.6.0/media-buy/sync-creatives-async-response-submitted.json +++ b/dist/schemas/2.6.0/media-buy/sync-creatives-async-response-submitted.json @@ -12,6 +12,5 @@ "$ref": "/schemas/2.6.0/core/ext.json" } }, - "additionalProperties": false + "additionalProperties": true } - diff --git a/dist/schemas/2.6.0/media-buy/sync-creatives-async-response-working.json b/dist/schemas/2.6.0/media-buy/sync-creatives-async-response-working.json index 64cb94257f..0ff7c3cc2e 100644 --- a/dist/schemas/2.6.0/media-buy/sync-creatives-async-response-working.json +++ b/dist/schemas/2.6.0/media-buy/sync-creatives-async-response-working.json @@ -42,6 +42,5 @@ "$ref": "/schemas/2.6.0/core/ext.json" } }, - "additionalProperties": false + "additionalProperties": true } - diff --git a/dist/schemas/2.6.0/media-buy/sync-creatives-request.json b/dist/schemas/2.6.0/media-buy/sync-creatives-request.json index e9d95a40e8..94cbff9d03 100644 --- a/dist/schemas/2.6.0/media-buy/sync-creatives-request.json +++ b/dist/schemas/2.6.0/media-buy/sync-creatives-request.json @@ -33,7 +33,7 @@ } } }, - "additionalProperties": false + "additionalProperties": true }, "delete_missing": { "type": "boolean", @@ -64,7 +64,7 @@ "required": [ "creatives" ], - "additionalProperties": false, + "additionalProperties": true, "examples": [ { "description": "Full sync with hosted video creative", @@ -135,7 +135,10 @@ { "description": "Scoped update using creative_ids filter", "data": { - "creative_ids": ["hero_video_30s", "banner_300x250"], + "creative_ids": [ + "hero_video_30s", + "banner_300x250" + ], "creatives": [ { "creative_id": "hero_video_30s", diff --git a/dist/schemas/2.6.0/media-buy/sync-creatives-response.json b/dist/schemas/2.6.0/media-buy/sync-creatives-response.json index d9ba729f07..8e8c894bba 100644 --- a/dist/schemas/2.6.0/media-buy/sync-creatives-response.json +++ b/dist/schemas/2.6.0/media-buy/sync-creatives-response.json @@ -79,14 +79,14 @@ "description": "Error message for this package assignment" } }, - "additionalProperties": false + "additionalProperties": true } }, "required": [ "creative_id", "action" ], - "additionalProperties": false + "additionalProperties": true } }, "context": { @@ -99,7 +99,7 @@ "required": [ "creatives" ], - "additionalProperties": false, + "additionalProperties": true, "not": { "required": [ "errors" @@ -129,7 +129,7 @@ "required": [ "errors" ], - "additionalProperties": false, + "additionalProperties": true, "not": { "anyOf": [ { diff --git a/dist/schemas/2.6.0/media-buy/update-media-buy-async-response-input-required.json b/dist/schemas/2.6.0/media-buy/update-media-buy-async-response-input-required.json index f9dfa75e12..a46decd07b 100644 --- a/dist/schemas/2.6.0/media-buy/update-media-buy-async-response-input-required.json +++ b/dist/schemas/2.6.0/media-buy/update-media-buy-async-response-input-required.json @@ -20,6 +20,5 @@ "$ref": "/schemas/2.6.0/core/ext.json" } }, - "additionalProperties": false + "additionalProperties": true } - diff --git a/dist/schemas/2.6.0/media-buy/update-media-buy-async-response-submitted.json b/dist/schemas/2.6.0/media-buy/update-media-buy-async-response-submitted.json index 15903c4f05..d76d16ec57 100644 --- a/dist/schemas/2.6.0/media-buy/update-media-buy-async-response-submitted.json +++ b/dist/schemas/2.6.0/media-buy/update-media-buy-async-response-submitted.json @@ -12,6 +12,5 @@ "$ref": "/schemas/2.6.0/core/ext.json" } }, - "additionalProperties": false + "additionalProperties": true } - diff --git a/dist/schemas/2.6.0/media-buy/update-media-buy-async-response-working.json b/dist/schemas/2.6.0/media-buy/update-media-buy-async-response-working.json index e0d39646df..1779120a8b 100644 --- a/dist/schemas/2.6.0/media-buy/update-media-buy-async-response-working.json +++ b/dist/schemas/2.6.0/media-buy/update-media-buy-async-response-working.json @@ -32,6 +32,5 @@ "$ref": "/schemas/2.6.0/core/ext.json" } }, - "additionalProperties": false + "additionalProperties": true } - diff --git a/dist/schemas/2.6.0/media-buy/update-media-buy-request.json b/dist/schemas/2.6.0/media-buy/update-media-buy-request.json index 7bb4495a5d..40033c5589 100644 --- a/dist/schemas/2.6.0/media-buy/update-media-buy-request.json +++ b/dist/schemas/2.6.0/media-buy/update-media-buy-request.json @@ -94,7 +94,7 @@ ] } ], - "additionalProperties": false + "additionalProperties": true } }, "push_notification_config": { @@ -120,5 +120,5 @@ ] } ], - "additionalProperties": false + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/media-buy/update-media-buy-response.json b/dist/schemas/2.6.0/media-buy/update-media-buy-response.json index 595f958ecc..8f2338be07 100644 --- a/dist/schemas/2.6.0/media-buy/update-media-buy-response.json +++ b/dist/schemas/2.6.0/media-buy/update-media-buy-response.json @@ -44,7 +44,7 @@ "media_buy_id", "buyer_ref" ], - "additionalProperties": false, + "additionalProperties": true, "not": { "required": [ "errors" @@ -74,7 +74,7 @@ "required": [ "errors" ], - "additionalProperties": false, + "additionalProperties": true, "not": { "anyOf": [ { diff --git a/dist/schemas/2.6.0/pricing-options/cpc-option.json b/dist/schemas/2.6.0/pricing-options/cpc-option.json index 69f9d8c11e..109b04024b 100644 --- a/dist/schemas/2.6.0/pricing-options/cpc-option.json +++ b/dist/schemas/2.6.0/pricing-options/cpc-option.json @@ -23,7 +23,12 @@ "type": "string", "description": "ISO 4217 currency code", "pattern": "^[A-Z]{3}$", - "examples": ["USD", "EUR", "GBP", "JPY"] + "examples": [ + "USD", + "EUR", + "GBP", + "JPY" + ] }, "is_fixed": { "type": "boolean", @@ -36,6 +41,12 @@ "minimum": 0 } }, - "required": ["pricing_option_id", "pricing_model", "rate", "currency", "is_fixed"], - "additionalProperties": false + "required": [ + "pricing_option_id", + "pricing_model", + "rate", + "currency", + "is_fixed" + ], + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/pricing-options/cpcv-option.json b/dist/schemas/2.6.0/pricing-options/cpcv-option.json index 96d2dd1dcd..811866ec5c 100644 --- a/dist/schemas/2.6.0/pricing-options/cpcv-option.json +++ b/dist/schemas/2.6.0/pricing-options/cpcv-option.json @@ -23,7 +23,12 @@ "type": "string", "description": "ISO 4217 currency code", "pattern": "^[A-Z]{3}$", - "examples": ["USD", "EUR", "GBP", "JPY"] + "examples": [ + "USD", + "EUR", + "GBP", + "JPY" + ] }, "is_fixed": { "type": "boolean", @@ -36,6 +41,12 @@ "minimum": 0 } }, - "required": ["pricing_option_id", "pricing_model", "rate", "currency", "is_fixed"], - "additionalProperties": false + "required": [ + "pricing_option_id", + "pricing_model", + "rate", + "currency", + "is_fixed" + ], + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/pricing-options/cpm-auction-option.json b/dist/schemas/2.6.0/pricing-options/cpm-auction-option.json index f3c85b2cee..6ebefa0196 100644 --- a/dist/schemas/2.6.0/pricing-options/cpm-auction-option.json +++ b/dist/schemas/2.6.0/pricing-options/cpm-auction-option.json @@ -18,7 +18,12 @@ "type": "string", "description": "ISO 4217 currency code", "pattern": "^[A-Z]{3}$", - "examples": ["USD", "EUR", "GBP", "JPY"] + "examples": [ + "USD", + "EUR", + "GBP", + "JPY" + ] }, "is_fixed": { "type": "boolean", @@ -55,7 +60,9 @@ "minimum": 0 } }, - "required": ["floor"] + "required": [ + "floor" + ] }, "min_spend_per_package": { "type": "number", @@ -63,6 +70,12 @@ "minimum": 0 } }, - "required": ["pricing_option_id", "pricing_model", "price_guidance", "currency", "is_fixed"], - "additionalProperties": false + "required": [ + "pricing_option_id", + "pricing_model", + "price_guidance", + "currency", + "is_fixed" + ], + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/pricing-options/cpm-fixed-option.json b/dist/schemas/2.6.0/pricing-options/cpm-fixed-option.json index 161ccada20..f5b6befc2b 100644 --- a/dist/schemas/2.6.0/pricing-options/cpm-fixed-option.json +++ b/dist/schemas/2.6.0/pricing-options/cpm-fixed-option.json @@ -23,7 +23,12 @@ "type": "string", "description": "ISO 4217 currency code", "pattern": "^[A-Z]{3}$", - "examples": ["USD", "EUR", "GBP", "JPY"] + "examples": [ + "USD", + "EUR", + "GBP", + "JPY" + ] }, "is_fixed": { "type": "boolean", @@ -36,6 +41,12 @@ "minimum": 0 } }, - "required": ["pricing_option_id", "pricing_model", "rate", "currency", "is_fixed"], - "additionalProperties": false + "required": [ + "pricing_option_id", + "pricing_model", + "rate", + "currency", + "is_fixed" + ], + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/pricing-options/cpp-option.json b/dist/schemas/2.6.0/pricing-options/cpp-option.json index b6ddc5a516..223f37fb54 100644 --- a/dist/schemas/2.6.0/pricing-options/cpp-option.json +++ b/dist/schemas/2.6.0/pricing-options/cpp-option.json @@ -23,7 +23,12 @@ "type": "string", "description": "ISO 4217 currency code", "pattern": "^[A-Z]{3}$", - "examples": ["USD", "EUR", "GBP", "JPY"] + "examples": [ + "USD", + "EUR", + "GBP", + "JPY" + ] }, "is_fixed": { "type": "boolean", @@ -45,8 +50,10 @@ "minimum": 0 } }, - "required": ["demographic"], - "additionalProperties": false + "required": [ + "demographic" + ], + "additionalProperties": true }, "min_spend_per_package": { "type": "number", @@ -54,6 +61,13 @@ "minimum": 0 } }, - "required": ["pricing_option_id", "pricing_model", "rate", "currency", "is_fixed", "parameters"], - "additionalProperties": false + "required": [ + "pricing_option_id", + "pricing_model", + "rate", + "currency", + "is_fixed", + "parameters" + ], + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/pricing-options/cpv-option.json b/dist/schemas/2.6.0/pricing-options/cpv-option.json index a8d9c715bb..3d37c7e0f5 100644 --- a/dist/schemas/2.6.0/pricing-options/cpv-option.json +++ b/dist/schemas/2.6.0/pricing-options/cpv-option.json @@ -23,7 +23,12 @@ "type": "string", "description": "ISO 4217 currency code", "pattern": "^[A-Z]{3}$", - "examples": ["USD", "EUR", "GBP", "JPY"] + "examples": [ + "USD", + "EUR", + "GBP", + "JPY" + ] }, "is_fixed": { "type": "boolean", @@ -52,14 +57,18 @@ "minimum": 1 } }, - "required": ["duration_seconds"], - "additionalProperties": false + "required": [ + "duration_seconds" + ], + "additionalProperties": true } ] } }, - "required": ["view_threshold"], - "additionalProperties": false + "required": [ + "view_threshold" + ], + "additionalProperties": true }, "min_spend_per_package": { "type": "number", @@ -67,6 +76,13 @@ "minimum": 0 } }, - "required": ["pricing_option_id", "pricing_model", "rate", "currency", "is_fixed", "parameters"], - "additionalProperties": false + "required": [ + "pricing_option_id", + "pricing_model", + "rate", + "currency", + "is_fixed", + "parameters" + ], + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/pricing-options/flat-rate-option.json b/dist/schemas/2.6.0/pricing-options/flat-rate-option.json index 9cffaa843a..12d145d72f 100644 --- a/dist/schemas/2.6.0/pricing-options/flat-rate-option.json +++ b/dist/schemas/2.6.0/pricing-options/flat-rate-option.json @@ -23,7 +23,12 @@ "type": "string", "description": "ISO 4217 currency code", "pattern": "^[A-Z]{3}$", - "examples": ["USD", "EUR", "GBP", "JPY"] + "examples": [ + "USD", + "EUR", + "GBP", + "JPY" + ] }, "is_fixed": { "type": "boolean", @@ -69,7 +74,7 @@ "description": "Specific daypart for time-based pricing (e.g., 'morning_commute', 'evening_prime', 'overnight')" } }, - "additionalProperties": false + "additionalProperties": true }, "min_spend_per_package": { "type": "number", @@ -77,6 +82,12 @@ "minimum": 0 } }, - "required": ["pricing_option_id", "pricing_model", "currency", "is_fixed", "rate"], - "additionalProperties": false + "required": [ + "pricing_option_id", + "pricing_model", + "currency", + "is_fixed", + "rate" + ], + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/pricing-options/vcpm-auction-option.json b/dist/schemas/2.6.0/pricing-options/vcpm-auction-option.json index 859cf9e8e5..324d73652a 100644 --- a/dist/schemas/2.6.0/pricing-options/vcpm-auction-option.json +++ b/dist/schemas/2.6.0/pricing-options/vcpm-auction-option.json @@ -18,7 +18,12 @@ "type": "string", "description": "ISO 4217 currency code", "pattern": "^[A-Z]{3}$", - "examples": ["USD", "EUR", "GBP", "JPY"] + "examples": [ + "USD", + "EUR", + "GBP", + "JPY" + ] }, "is_fixed": { "type": "boolean", @@ -55,7 +60,9 @@ "minimum": 0 } }, - "required": ["floor"] + "required": [ + "floor" + ] }, "min_spend_per_package": { "type": "number", @@ -63,6 +70,12 @@ "minimum": 0 } }, - "required": ["pricing_option_id", "pricing_model", "currency", "price_guidance", "is_fixed"], - "additionalProperties": false + "required": [ + "pricing_option_id", + "pricing_model", + "currency", + "price_guidance", + "is_fixed" + ], + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/pricing-options/vcpm-fixed-option.json b/dist/schemas/2.6.0/pricing-options/vcpm-fixed-option.json index 5b554bd475..2905d94dd3 100644 --- a/dist/schemas/2.6.0/pricing-options/vcpm-fixed-option.json +++ b/dist/schemas/2.6.0/pricing-options/vcpm-fixed-option.json @@ -23,7 +23,12 @@ "type": "string", "description": "ISO 4217 currency code", "pattern": "^[A-Z]{3}$", - "examples": ["USD", "EUR", "GBP", "JPY"] + "examples": [ + "USD", + "EUR", + "GBP", + "JPY" + ] }, "is_fixed": { "type": "boolean", @@ -36,6 +41,12 @@ "minimum": 0 } }, - "required": ["pricing_option_id", "pricing_model", "rate", "currency", "is_fixed"], - "additionalProperties": false + "required": [ + "pricing_option_id", + "pricing_model", + "rate", + "currency", + "is_fixed" + ], + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/protocols/adcp-extension.json b/dist/schemas/2.6.0/protocols/adcp-extension.json index 6dc0abc5ea..3d31caf104 100644 --- a/dist/schemas/2.6.0/protocols/adcp-extension.json +++ b/dist/schemas/2.6.0/protocols/adcp-extension.json @@ -14,13 +14,20 @@ "type": "array", "items": { "type": "string", - "enum": ["media_buy", "creative", "signals"] + "enum": [ + "media_buy", + "creative", + "signals" + ] }, "minItems": 1, "uniqueItems": true, "description": "AdCP protocol domains supported by this agent. At least one must be specified." } }, - "required": ["adcp_version", "protocols_supported"], - "additionalProperties": false + "required": [ + "adcp_version", + "protocols_supported" + ], + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/signals/activate-signal-request.json b/dist/schemas/2.6.0/signals/activate-signal-request.json index 6f6684fdd8..b262f187a8 100644 --- a/dist/schemas/2.6.0/signals/activate-signal-request.json +++ b/dist/schemas/2.6.0/signals/activate-signal-request.json @@ -28,5 +28,5 @@ "signal_agent_segment_id", "deployments" ], - "additionalProperties": false + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/signals/activate-signal-response.json b/dist/schemas/2.6.0/signals/activate-signal-response.json index 8d09d78783..06b773eb9d 100644 --- a/dist/schemas/2.6.0/signals/activate-signal-response.json +++ b/dist/schemas/2.6.0/signals/activate-signal-response.json @@ -27,7 +27,7 @@ "required": [ "deployments" ], - "additionalProperties": false, + "additionalProperties": true, "not": { "required": [ "errors" @@ -57,7 +57,7 @@ "required": [ "errors" ], - "additionalProperties": false, + "additionalProperties": true, "not": { "required": [ "deployments" diff --git a/dist/schemas/2.6.0/signals/get-signals-request.json b/dist/schemas/2.6.0/signals/get-signals-request.json index 638bfa8c5f..bcb4597f02 100644 --- a/dist/schemas/2.6.0/signals/get-signals-request.json +++ b/dist/schemas/2.6.0/signals/get-signals-request.json @@ -34,7 +34,7 @@ "deployments", "countries" ], - "additionalProperties": false + "additionalProperties": true }, "filters": { "$ref": "/schemas/2.6.0/core/signal-filters.json" @@ -55,5 +55,5 @@ "signal_spec", "deliver_to" ], - "additionalProperties": false + "additionalProperties": true } diff --git a/dist/schemas/2.6.0/signals/get-signals-response.json b/dist/schemas/2.6.0/signals/get-signals-response.json index 657ca19f3a..2751dd8455 100644 --- a/dist/schemas/2.6.0/signals/get-signals-response.json +++ b/dist/schemas/2.6.0/signals/get-signals-response.json @@ -63,7 +63,7 @@ "cpm", "currency" ], - "additionalProperties": false + "additionalProperties": true } }, "required": [ @@ -76,7 +76,7 @@ "deployments", "pricing" ], - "additionalProperties": false + "additionalProperties": true } }, "errors": { @@ -96,5 +96,5 @@ "required": [ "signals" ], - "additionalProperties": false + "additionalProperties": true } diff --git a/static/schemas/source/index.json b/static/schemas/source/index.json index 2e89bca9ce..6ea9e42a77 100644 --- a/static/schemas/source/index.json +++ b/static/schemas/source/index.json @@ -4,7 +4,7 @@ "title": "AdCP Schema Registry v1", "version": "1.0.0", "description": "Registry of all AdCP JSON schemas for validation and discovery", -"adcp_version": "2.6.0", + "adcp_version": "2.6.0", "standard_formats_version": "2.0.0", "versioning": { "note": "AdCP uses path-based versioning. The schema URL path (/schemas/) indicates the version. Individual request/response schemas do NOT include adcp_version fields. Compatibility follows semantic versioning rules." From c94fe34c03463370f01dcd61ade2713a8414cf07 Mon Sep 17 00:00:00 2001 From: Brian O'Kelley Date: Thu, 8 Jan 2026 18:44:21 -0800 Subject: [PATCH 15/34] feat: Add typed extensions infrastructure with auto-discovery (#648) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: Add typed extensions infrastructure with auto-discovery Typed extensions provide formal JSON schemas for vendor-agnostic extension data in `ext.{namespace}` fields. This enables SDK code generation, schema validation, and cross-vendor interoperability. **New features:** - Extension meta schema defining valid_from/valid_until version bounds - Auto-discovery of extensions during schema build - Version-filtered extension registries per schema version - New `extensions_supported` field in agent card adcp extension - Comprehensive test suite for extension infrastructure **How it works:** 1. Extensions are defined in `/schemas/source/extensions/{namespace}.json` 2. Build script auto-discovers extensions and filters by version compatibility 3. Each versioned build includes only compatible extensions in registry 4. Agents declare supported extensions via `extensions_supported` array This is a MINOR release adding new optional capabilities without breaking existing functionality. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * docs: Fix A2A extension format and add MCP server card support Updates documentation to be compliant with both protocol specs: **A2A Agent Cards:** - Changed from `extensions.adcp` object to proper A2A `extensions[]` array format - Each extension now has uri, description, required, and params fields - Extension URI: https://adcontextprotocol.org/extensions/adcp **MCP Server Cards:** - Added support for declaring AdCP via `_meta['adcontextprotocol.org']` - Supports both `/.well-known/mcp.json` and `/.well-known/server.json` - Uses reverse DNS namespacing per MCP server.json spec **Extension Params Schema:** - Updated description to clarify usage in both protocols - Same params structure works for both A2A and MCP 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * fix: Remove external $schema reference from MCP server card examples The JSON schema validation test was failing because it tried to validate against https://registry.modelcontextprotocol.io/server.schema.json which is an external schema we don't have locally. Removed the $schema field from MCP server card examples since they reference an external MCP registry schema, not an AdCP schema. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * feat: Add reserved namespaces and deprecation policy for extensions Addresses PR review feedback: **Reserved Namespaces (@BaiyuScope3)** - Added RESERVED_NAMESPACES list: adcp, core, protocol, schema, meta, ext, context - Build script now validates and rejects reserved namespaces - Documented in extensions reference **Deprecation Policy (@BaiyuScope3)** - Added "Extension Deprecation Policy" section with: - When extensions may be deprecated (superseded, promoted, low adoption, incompatible) - Standard deprecation process (valid_until + 1 minor, CHANGELOG, migration guide) - Emergency deprecation for security issues **Tests** - Added test verifying reserved namespaces are not used 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --------- Co-authored-by: Claude Opus 4.5 --- docs/protocols/a2a-guide.mdx | 39 +- docs/protocols/mcp-guide.mdx | 52 +- docs/reference/extensions-and-context.mdx | 207 ++++++++ package.json | 3 +- scripts/build-schemas.cjs | 252 ++++++++++ .../source/extensions/extension-meta.json | 59 +++ static/schemas/source/extensions/index.json | 9 + static/schemas/source/index.json | 14 +- .../source/protocols/adcp-extension.json | 16 +- tests/extension-schemas.test.cjs | 445 ++++++++++++++++++ 10 files changed, 1074 insertions(+), 22 deletions(-) create mode 100644 static/schemas/source/extensions/extension-meta.json create mode 100644 static/schemas/source/extensions/index.json create mode 100644 tests/extension-schemas.test.cjs diff --git a/docs/protocols/a2a-guide.mdx b/docs/protocols/a2a-guide.mdx index 8bfe9b4f54..f66867dc49 100644 --- a/docs/protocols/a2a-guide.mdx +++ b/docs/protocols/a2a-guide.mdx @@ -711,32 +711,51 @@ console.log('Examples:', getProductsSkill.examples); ] } ], - "extensions": { - "adcp": { - "adcp_version": "2.4.0", - "protocols_supported": ["media_buy"] + "extensions": [ + { + "uri": "https://adcontextprotocol.org/extensions/adcp", + "description": "AdCP media buying protocol support", + "required": false, + "params": { + "adcp_version": "2.6.0", + "protocols_supported": ["media_buy"], + "extensions_supported": ["sustainability"] + } } - } + ] } ``` ### AdCP Extension -**Recommended**: Include the `extensions.adcp` field in your agent card to declare AdCP support programmatically. +**Recommended**: Include the AdCP extension in your agent card's `extensions` array to declare AdCP support programmatically. + +The A2A protocol uses an `extensions` array where each extension has: +- **`uri`**: Extension identifier (use `https://adcontextprotocol.org/extensions/adcp`) +- **`description`**: Human-readable description of how you use AdCP +- **`required`**: Whether clients must support this extension (typically `false` for AdCP) +- **`params`**: AdCP-specific configuration (see schema below) ```javascript // Check if agent supports AdCP const agentCard = await fetch('https://sales.example.com/.well-known/agent.json') .then(r => r.json()); -if (agentCard.extensions?.adcp) { - console.log('AdCP Version:', agentCard.extensions.adcp.adcp_version); - console.log('Supported domains:', agentCard.extensions.adcp.protocols_supported); +// Find the AdCP extension in the extensions array +const adcpExt = agentCard.extensions?.find( + ext => ext.uri === 'https://adcontextprotocol.org/extensions/adcp' +); + +if (adcpExt) { + console.log('AdCP Version:', adcpExt.params.adcp_version); + console.log('Supported domains:', adcpExt.params.protocols_supported); // ["media_buy", "creative", "signals"] + console.log('Typed extensions:', adcpExt.params.extensions_supported); + // ["sustainability"] } ``` -**Extension Structure**: See the [AdCP extension schema](https://adcontextprotocol.org/schemas/v2/protocols/adcp-extension.json) for complete specification. +**Extension Params Schema**: See the [AdCP extension schema](https://adcontextprotocol.org/schemas/v2/protocols/adcp-extension.json) for the complete `params` specification. **Benefits**: - Clients can discover AdCP capabilities without making test calls diff --git a/docs/protocols/mcp-guide.mdx b/docs/protocols/mcp-guide.mdx index c3303454dd..a8581b776e 100644 --- a/docs/protocols/mcp-guide.mdx +++ b/docs/protocols/mcp-guide.mdx @@ -632,22 +632,60 @@ const adcpTools = tools.filter(t => t.name.startsWith('adcp_') || ['get_products', 'create_media_buy'].includes(t.name)); ``` -### AdCP Extension (Future) +### AdCP Extension via MCP Server Card -**Status**: MCP server cards are expected in a future MCP release. When available, AdCP servers will include the AdCP extension. +MCP servers can declare AdCP support via a server card at `/.well-known/mcp.json` (or `/.well-known/server.json`). AdCP-specific metadata goes in the `_meta` field using the `adcontextprotocol.org` namespace. ```json { - "extensions": { - "adcp": { - "adcp_version": "2.4.0", - "protocols_supported": ["media_buy", "creative", "signals"] + "name": "io.adcontextprotocol/media-buy-agent", + "version": "1.0.0", + "title": "AdCP Media Buy Agent", + "description": "AI-powered media buying agent implementing AdCP", + "tools": [ + { "name": "get_products" }, + { "name": "create_media_buy" }, + { "name": "list_creative_formats" } + ], + "_meta": { + "adcontextprotocol.org": { + "adcp_version": "2.6.0", + "protocols_supported": ["media_buy"], + "extensions_supported": ["sustainability"] } } } ``` -This will allow clients to programmatically discover which AdCP version and protocol domains an MCP server implements. See the [AdCP extension schema](https://adcontextprotocol.org/schemas/v2/protocols/adcp-extension.json) for specification details. +**Discovering AdCP support:** + +```javascript +// Check both possible locations for MCP server card +const serverCard = await fetch('https://sales.example.com/.well-known/mcp.json') + .then(r => r.ok ? r.json() : null) + .catch(() => null) + || await fetch('https://sales.example.com/.well-known/server.json') + .then(r => r.json()); + +// Check for AdCP metadata +const adcpMeta = serverCard?._meta?.['adcontextprotocol.org']; + +if (adcpMeta) { + console.log('AdCP Version:', adcpMeta.adcp_version); + console.log('Supported domains:', adcpMeta.protocols_supported); + // ["media_buy", "creative", "signals"] + console.log('Typed extensions:', adcpMeta.extensions_supported); + // ["sustainability"] +} +``` + +**Benefits:** +- Clients can discover AdCP capabilities without making test calls +- Declare which protocol domains you implement (media_buy, creative, signals) +- Declare which [typed extensions](/docs/reference/extensions-and-context#typed-extensions) you support +- Enable compatibility checks based on version + +**Note:** The `_meta` field uses reverse DNS namespacing per the [MCP server.json spec](https://github.com/modelcontextprotocol/registry/blob/main/docs/reference/server-json/generic-server-json.md). AdCP servers should support both `/.well-known/mcp.json` and `/.well-known/server.json` locations. ### Parameter Validation ```javascript diff --git a/docs/reference/extensions-and-context.mdx b/docs/reference/extensions-and-context.mdx index 48484c0201..e29ec563c3 100644 --- a/docs/reference/extensions-and-context.mdx +++ b/docs/reference/extensions-and-context.mdx @@ -181,6 +181,213 @@ Without namespacing: - Impossible to support multiple platforms simultaneously - Harder to deprecate platform-specific features +## Typed Extensions + +AdCP supports formal JSON schemas for extensions, enabling type safety and validation. Typed extensions are published in the `/schemas/extensions/` directory and can be declared in agent cards. + +### How Typed Extensions Work + +Typed extensions provide a middle ground between untyped vendor extensions and core AdCP fields: + +- **Untyped extensions** (`ext.vendor.*`) - Any JSON, no validation, vendor-specific +- **Typed extensions** (`ext.sustainability.*`) - Formal schema, validated, cross-vendor +- **Core fields** - Part of AdCP specification, required for interoperability + +Typed extensions enable SDK code generation, schema validation, and cross-vendor interoperability while remaining optional. + +### Extension Schema Registry + +The registry of available typed extensions is auto-generated from extension files: +- **Registry**: `/schemas/v1/extensions/index.json` +- **Extension schemas**: `/schemas/v1/extensions/{namespace}.json` +- **Meta schema**: `/schemas/v1/extensions/extension-meta.json` + +Each versioned schema path (`/schemas/v2.5/`, `/schemas/v2.6/`) includes only extensions valid for that version, based on the `valid_from` and `valid_until` fields in each extension. + +### Extension Versioning + +Extensions are versioned independently of the AdCP specification: + +```json +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/extensions/sustainability.json", + "title": "Sustainability Extension", + "description": "Carbon footprint and green certification data", + "valid_from": "2.5", + "valid_until": "4.0", + "docs_url": "https://adcontextprotocol.org/docs/extensions/sustainability", + "type": "object", + "properties": { + "carbon_kg_per_impression": { "type": "number" }, + "certified_green": { "type": "boolean" } + } +} +``` + +- **`valid_from`** (required): Minimum AdCP version this extension works with (e.g., `"2.5"`) +- **`valid_until`** (optional): Last AdCP version this extension works with. Omit if still valid. + +This allows extensions to be backported to earlier AdCP versions and deprecated gracefully. + +### Declaring Extension Support + +Agents declare which typed extensions they support in their discovery metadata. The location depends on the protocol: + +#### A2A Agent Cards + +A2A agents declare AdCP support in the `extensions` array at `/.well-known/agent.json`: + +```json +{ + "name": "AdCP Media Buy Agent", + "skills": [{ "name": "get_products" }, { "name": "create_media_buy" }], + "extensions": [ + { + "uri": "https://adcontextprotocol.org/extensions/adcp", + "description": "AdCP media buying protocol support", + "required": false, + "params": { + "adcp_version": "2.6.0", + "protocols_supported": ["media_buy"], + "extensions_supported": ["sustainability"] + } + } + ] +} +``` + +See the [A2A Guide](/docs/protocols/a2a-guide#adcp-extension) for complete details. + +#### MCP Server Cards + +MCP servers declare AdCP support via the `_meta` field at `/.well-known/mcp.json` or `/.well-known/server.json`: + +```json +{ + "name": "io.adcontextprotocol/media-buy-agent", + "tools": [{ "name": "get_products" }, { "name": "create_media_buy" }], + "_meta": { + "adcontextprotocol.org": { + "adcp_version": "2.6.0", + "protocols_supported": ["media_buy"], + "extensions_supported": ["sustainability"] + } + } +} +``` + +See the [MCP Guide](/docs/protocols/mcp-guide#adcp-extension-via-mcp-server-card) for complete details. + +#### Extension Params Schema + +Both protocols use the same params structure, defined in the [AdCP extension schema](https://adcontextprotocol.org/schemas/v2/protocols/adcp-extension.json): +- **`adcp_version`** (required): Semantic version of AdCP implemented (e.g., "2.6.0") +- **`protocols_supported`** (required): Array of protocol domains (media_buy, creative, signals) +- **`extensions_supported`** (optional): Array of typed extension namespaces + +When an agent declares support for an extension, clients can expect: +- The agent will accept and populate `ext.{namespace}` fields conforming to that extension's schema +- Data in `ext.{namespace}` is strongly typed and can be validated +- SDK code generation can produce type-safe interfaces for the extension + +### Using Typed Extensions + +When an agent supports a typed extension, you can include and expect data in the corresponding namespace: + +```json +{ + "product_id": "premium_ctv", + "name": "Premium CTV Package", + "ext": { + "sustainability": { + "carbon_kg_per_impression": 0.0012, + "certified_green": true + } + } +} +``` + +### Creating a Typed Extension + +To create a typed extension: + +1. **Create the extension file** at `/schemas/extensions/{namespace}.json` +2. **Follow the meta schema** defined in `/schemas/extensions/extension-meta.json` +3. **Set `valid_from`** to the minimum AdCP version your extension requires +4. **Add documentation** via the `docs_url` field + +Example extension file: + +```json +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/extensions/sustainability.json", + "title": "Sustainability Extension", + "description": "Carbon footprint and green certification data for ad products", + "valid_from": "2.5", + "docs_url": "https://adcontextprotocol.org/docs/extensions/sustainability", + "type": "object", + "properties": { + "carbon_kg_per_impression": { + "type": "number", + "description": "Estimated CO2 emissions per impression in kilograms" + }, + "certified_green": { + "type": "boolean", + "description": "Whether the inventory is certified by a green advertising program" + }, + "certification_provider": { + "type": "string", + "description": "Name of the green certification provider" + } + } +} +``` + +The build process auto-discovers extension files and includes them in the appropriate versioned schema builds. + +### Proposing Typed Extensions + +To propose a typed extension for inclusion in AdCP: + +1. **Validate in production first** - Use vendor-namespaced extensions (`ext.yourcompany.*`) to prove value +2. **Document the schema** - Define clear property names, types, and descriptions +3. **Gather adoption evidence** - Show multiple implementations or strong demand +4. **Submit an RFC** - Propose the extension with schema and use cases +5. **If accepted** - Extension is added to `/schemas/extensions/` with appropriate `valid_from` + +### Reserved Namespaces + +The following namespaces are reserved and cannot be used for typed extensions: +- `adcp`, `core`, `protocol`, `schema`, `meta`, `ext`, `context` + +These are reserved to prevent confusion with core AdCP concepts. + +### Extension Deprecation Policy + +#### When Extensions May Be Deprecated + +1. **Superseded** - A better extension exists with a documented migration path +2. **Promoted to core** - The extension becomes a core AdCP field +3. **Low adoption** - Insufficient usage across implementations +4. **Incompatible** - Breaking changes in AdCP require removal + +#### Deprecation Process + +1. Set `valid_until` to current version + 1 minor release (minimum grace period) +2. Announce deprecation in CHANGELOG +3. Publish migration guide if replacement exists +4. Add deprecation warning to extension docs +5. Extension removed from builds after `valid_until` version + +#### Emergency Deprecation + +Security issues may require immediate deprecation: +- `valid_until` set to current version +- Security advisory published +- Patch release issued + ## Proposing Spec Additions If your extension field represents **common ad tech functionality** that would benefit all AdCP implementations: diff --git a/package.json b/package.json index 5303772f60..3528a0e731 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "test:schemas": "node tests/schema-validation.test.cjs", "test:examples": "node tests/example-validation-simple.test.cjs", "test:extensions": "node tests/extension-fields.test.cjs", + "test:extension-schemas": "node tests/extension-schemas.test.cjs", "test:snippets": "node tests/snippet-validation.test.cjs", "test:json-schema": "node tests/json-schema-validation.test.cjs", "test:error-handling": "node tests/check-error-handling.cjs", @@ -27,7 +28,7 @@ "test:registry": "vitest run server/tests", "test:docker": "docker compose -f docker-compose.test.yml up --build --abort-on-container-exit", "generate-openapi": "node scripts/generate-openapi.cjs", - "test": "npm run test:schemas && npm run test:examples && npm run test:extensions && npm run test:error-handling && npm run test:json-schema && npm run test:composed && npm run test:migrations && npm run test:unit && npm run typecheck", + "test": "npm run test:schemas && npm run test:examples && npm run test:extensions && npm run test:extension-schemas && npm run test:error-handling && npm run test:json-schema && npm run test:composed && npm run test:migrations && npm run test:unit && npm run typecheck", "test:all": "npm run test:schemas && npm run test:examples && npm run test:extensions && npm run test:error-handling && npm run test:snippets && npm run typecheck", "precommit": "npm test", "prepare": "husky", diff --git a/scripts/build-schemas.cjs b/scripts/build-schemas.cjs index b915b37b32..80bad287c6 100644 --- a/scripts/build-schemas.cjs +++ b/scripts/build-schemas.cjs @@ -21,6 +21,11 @@ * - /schemas/v{major}/ - Points to latest release of that major version * - /schemas/v{major}.{minor}/ - Points to latest release of that minor version * - /schemas/v1/ - Backward compatibility (always points to latest/) + * + * Extension handling: + * - Extensions are auto-discovered from static/schemas/source/extensions/ + * - Each extension has valid_from/valid_until to specify compatible AdCP versions + * - The build generates extensions/index.json with extensions valid for the target version */ const fs = require('fs'); @@ -109,6 +114,228 @@ function ensureDir(dir) { } } +/** + * Compare two minor versions (e.g., "2.5" vs "2.6") + * Returns: negative if a < b, 0 if equal, positive if a > b + */ +function compareMinorVersions(a, b) { + const [aMajor, aMinor] = a.split('.').map(Number); + const [bMajor, bMinor] = b.split('.').map(Number); + if (aMajor !== bMajor) return aMajor - bMajor; + return aMinor - bMinor; +} + +/** + * Reserved namespaces that cannot be used for typed extensions + * These could cause confusion with core AdCP concepts + */ +const RESERVED_NAMESPACES = ['adcp', 'core', 'protocol', 'schema', 'meta', 'ext', 'context']; + +/** + * Validate that an extension namespace is not reserved + * @param {string} namespace - Extension namespace to validate + * @throws {Error} If namespace is reserved + */ +function validateExtensionNamespace(namespace) { + if (RESERVED_NAMESPACES.includes(namespace.toLowerCase())) { + throw new Error(`Namespace "${namespace}" is reserved and cannot be used for extensions`); + } +} + +/** + * Discover extension files from the extensions directory + * Returns array of { namespace, schema, path } objects + */ +function discoverExtensions(extensionsDir) { + if (!fs.existsSync(extensionsDir)) { + return []; + } + + const extensions = []; + const files = fs.readdirSync(extensionsDir); + + for (const file of files) { + // Skip non-JSON files and special files + if (!file.endsWith('.json')) continue; + if (file === 'index.json' || file === 'extension-meta.json') continue; + + const filePath = path.join(extensionsDir, file); + try { + const content = JSON.parse(fs.readFileSync(filePath, 'utf8')); + + // Extract namespace from $id (e.g., /schemas/extensions/sustainability.json -> sustainability) + const namespace = file.replace('.json', ''); + + // Validate namespace is not reserved + validateExtensionNamespace(namespace); + + extensions.push({ + namespace, + schema: content, + path: filePath + }); + } catch (error) { + console.warn(` ⚠️ Failed to parse extension ${file}: ${error.message}`); + } + } + + return extensions; +} + +/** + * Filter extensions to those valid for a given AdCP version + * @param {Array} extensions - Array of extension objects from discoverExtensions + * @param {string} targetVersion - Target AdCP version (e.g., "2.5.0" or "2.5") + * @returns {Array} Extensions valid for the target version + */ +function filterExtensionsForVersion(extensions, targetVersion) { + // Normalize to minor version for comparison + const targetMinor = getMinorVersion(targetVersion); + + return extensions.filter(ext => { + const { valid_from, valid_until } = ext.schema; + + // Must have valid_from + if (!valid_from) { + console.warn(` ⚠️ Extension ${ext.namespace} missing valid_from, skipping`); + return false; + } + + // Check valid_from <= targetVersion + if (compareMinorVersions(valid_from, targetMinor) > 0) { + return false; // Extension requires newer version + } + + // Check valid_until >= targetVersion (if specified) + if (valid_until && compareMinorVersions(valid_until, targetMinor) < 0) { + return false; // Extension no longer valid for this version + } + + return true; + }); +} + +/** + * Generate the extensions/index.json registry for a target version + * @param {Array} extensions - Array of valid extension objects + * @param {string} targetVersion - Target version string for $id paths + * @returns {Object} The generated registry object + */ +function generateExtensionRegistry(extensions, targetVersion) { + const registry = { + $schema: 'http://json-schema.org/draft-07/schema#', + $id: `/schemas/${targetVersion}/extensions/index.json`, + title: 'AdCP Extension Registry', + description: 'Auto-generated registry of formal AdCP extensions. Extensions provide typed schemas for vendor-specific or domain-specific data within the ext field. Agents declare which extensions they support in their agent card.', + _generated: true, + _generatedAt: new Date().toISOString(), + extensions: {} + }; + + for (const ext of extensions) { + registry.extensions[ext.namespace] = { + $ref: `/schemas/${targetVersion}/extensions/${ext.namespace}.json`, + title: ext.schema.title, + description: ext.schema.description, + valid_from: ext.schema.valid_from + }; + + // Include valid_until if specified + if (ext.schema.valid_until) { + registry.extensions[ext.namespace].valid_until = ext.schema.valid_until; + } + + // Include docs_url if specified + if (ext.schema.docs_url) { + registry.extensions[ext.namespace].docs_url = ext.schema.docs_url; + } + } + + return registry; +} + +/** + * Build extensions for a target directory + * - Discovers all extensions from source + * - Filters to those valid for target version + * - Copies valid extension schemas + * - Generates the index.json registry + */ +function buildExtensions(sourceDir, targetDir, version) { + const sourceExtensionsDir = path.join(sourceDir, 'extensions'); + const targetExtensionsDir = path.join(targetDir, 'extensions'); + + // Always ensure extensions directory exists + ensureDir(targetExtensionsDir); + + // Discover all extensions + const allExtensions = discoverExtensions(sourceExtensionsDir); + + if (allExtensions.length === 0) { + // No extensions yet - just copy the meta schema and generate empty registry + const metaSchemaPath = path.join(sourceExtensionsDir, 'extension-meta.json'); + if (fs.existsSync(metaSchemaPath)) { + let content = fs.readFileSync(metaSchemaPath, 'utf8'); + // Update $id to include version + content = content.replace( + /"\$id":\s*"\/schemas\//g, + `"$id": "/schemas/${version}/` + ); + fs.writeFileSync(path.join(targetExtensionsDir, 'extension-meta.json'), content); + } + + // Generate empty registry + const registry = generateExtensionRegistry([], version); + fs.writeFileSync( + path.join(targetExtensionsDir, 'index.json'), + JSON.stringify(registry, null, 2) + ); + + return { total: 0, included: 0 }; + } + + // Filter extensions valid for this version + const validExtensions = filterExtensionsForVersion(allExtensions, version); + + // Copy extension-meta.json (with version transform) + const metaSchemaPath = path.join(sourceExtensionsDir, 'extension-meta.json'); + if (fs.existsSync(metaSchemaPath)) { + let content = fs.readFileSync(metaSchemaPath, 'utf8'); + content = content.replace( + /"\$id":\s*"\/schemas\//g, + `"$id": "/schemas/${version}/` + ); + fs.writeFileSync(path.join(targetExtensionsDir, 'extension-meta.json'), content); + } + + // Copy each valid extension schema (with version transform) + for (const ext of validExtensions) { + let content = JSON.stringify(ext.schema, null, 2); + // Update $id to include version + content = content.replace( + /"\$id":\s*"\/schemas\//g, + `"$id": "/schemas/${version}/` + ); + fs.writeFileSync( + path.join(targetExtensionsDir, `${ext.namespace}.json`), + content + ); + } + + // Generate the registry index + const registry = generateExtensionRegistry(validExtensions, version); + fs.writeFileSync( + path.join(targetExtensionsDir, 'index.json'), + JSON.stringify(registry, null, 2) + ); + + return { + total: allExtensions.length, + included: validExtensions.length, + extensions: validExtensions.map(e => e.namespace) + }; +} + function copyAndTransformSchemas(sourceDir, targetDir, version) { const entries = fs.readdirSync(sourceDir, { withFileTypes: true }); @@ -117,6 +344,10 @@ function copyAndTransformSchemas(sourceDir, targetDir, version) { const targetPath = path.join(targetDir, entry.name); if (entry.isDirectory()) { + // Skip extensions directory - handled separately by buildExtensions() + if (entry.name === 'extensions') { + continue; + } ensureDir(targetPath); copyAndTransformSchemas(sourcePath, targetPath, version); } else if (entry.name.endsWith('.json')) { @@ -332,6 +563,15 @@ async function main() { ensureDir(versionDir); copyAndTransformSchemas(SOURCE_DIR, versionDir, version); + // Build extensions (auto-discovered, filtered by version) + console.log(`🔌 Building extensions for ${version}`); + const extResult = buildExtensions(SOURCE_DIR, versionDir, version); + if (extResult.total === 0) { + console.log(` ✓ No extensions defined yet (empty registry created)`); + } else { + console.log(` ✓ Included ${extResult.included}/${extResult.total} extensions: ${extResult.extensions.join(', ') || 'none'}`); + } + // Generate bundled schemas for release const bundledDir = path.join(versionDir, 'bundled'); console.log(`📦 Generating bundled schemas to dist/schemas/${version}/bundled/`); @@ -350,6 +590,9 @@ async function main() { ensureDir(latestDir); copyAndTransformSchemas(SOURCE_DIR, latestDir, 'latest'); + // Build extensions for latest (using full version for filtering) + buildExtensions(SOURCE_DIR, latestDir, version); + // Generate bundled schemas for latest const latestBundledDir = path.join(latestDir, 'bundled'); await generateBundledSchemas(SOURCE_DIR, latestBundledDir, 'latest'); @@ -395,6 +638,15 @@ async function main() { ensureDir(latestDir); copyAndTransformSchemas(SOURCE_DIR, latestDir, 'latest'); + // Build extensions (auto-discovered, filtered by current version) + console.log(`🔌 Building extensions for ${version}`); + const extResult = buildExtensions(SOURCE_DIR, latestDir, version); + if (extResult.total === 0) { + console.log(` ✓ No extensions defined yet (empty registry created)`); + } else { + console.log(` ✓ Included ${extResult.included}/${extResult.total} extensions: ${extResult.extensions.join(', ') || 'none'}`); + } + // Generate bundled schemas for latest const bundledDir = path.join(latestDir, 'bundled'); console.log(`📦 Generating bundled schemas to dist/schemas/latest/bundled/`); diff --git a/static/schemas/source/extensions/extension-meta.json b/static/schemas/source/extensions/extension-meta.json new file mode 100644 index 0000000000..75e199a579 --- /dev/null +++ b/static/schemas/source/extensions/extension-meta.json @@ -0,0 +1,59 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/extensions/extension-meta.json", + "title": "AdCP Extension File Schema", + "description": "Schema that all extension files must follow. Combines metadata (valid_from, docs_url) with the actual extension data schema. Extensions are auto-discovered from /schemas/extensions/*.json and included in versioned builds based on valid_from/valid_until.", + "type": "object", + "properties": { + "$schema": { + "type": "string", + "const": "http://json-schema.org/draft-07/schema#" + }, + "$id": { + "type": "string", + "pattern": "^/schemas/extensions/[a-z][a-z0-9_]*\\.json$", + "description": "Extension ID following pattern /schemas/extensions/{namespace}.json" + }, + "title": { + "type": "string", + "description": "Human-readable title for the extension" + }, + "description": { + "type": "string", + "description": "Description of what this extension provides" + }, + "valid_from": { + "type": "string", + "pattern": "^\\d+\\.\\d+$", + "description": "Minimum AdCP version this extension is compatible with (e.g., '2.5'). Extension will be included in all versioned schema builds >= this version." + }, + "valid_until": { + "type": "string", + "pattern": "^\\d+\\.\\d+$", + "description": "Last AdCP version this extension is compatible with (e.g., '3.0'). Omit if extension is still valid for current and future versions." + }, + "docs_url": { + "type": "string", + "format": "uri", + "description": "URL to documentation for implementors of this extension" + }, + "type": { + "const": "object", + "description": "Extensions must be objects (data within ext.{namespace})" + }, + "properties": { + "type": "object", + "description": "Schema properties defining the structure of ext.{namespace} data", + "additionalProperties": true + }, + "required": { + "type": "array", + "items": { "type": "string" }, + "description": "Required properties within the extension data" + }, + "additionalProperties": { + "description": "Whether additional properties are allowed in the extension data" + } + }, + "required": ["$schema", "$id", "title", "description", "valid_from", "type", "properties"] +} diff --git a/static/schemas/source/extensions/index.json b/static/schemas/source/extensions/index.json new file mode 100644 index 0000000000..9b393e9ad2 --- /dev/null +++ b/static/schemas/source/extensions/index.json @@ -0,0 +1,9 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/extensions/index.json", + "title": "AdCP Extension Registry", + "description": "Auto-generated registry of formal AdCP extensions. Extensions provide typed schemas for vendor-specific or domain-specific data within the ext field. Agents declare which extensions they support in their agent card.", + "_generated": true, + "_note": "This file is auto-generated by the build process. Do not edit manually. Add extensions by creating new .json files in this directory following extension-meta.json schema.", + "extensions": {} +} diff --git a/static/schemas/source/index.json b/static/schemas/source/index.json index 6ea9e42a77..7a0db1fbd7 100644 --- a/static/schemas/source/index.json +++ b/static/schemas/source/index.json @@ -573,9 +573,21 @@ "schemas": { "adcp-extension": { "$ref": "/schemas/protocols/adcp-extension.json", - "description": "AdCP extension for agent cards (MCP and A2A). Declares AdCP version and supported protocol domains." + "description": "AdCP extension for agent cards (MCP and A2A). Declares AdCP version, supported protocol domains, and typed extensions." } } + }, + "extensions": { + "description": "Typed extension schemas for vendor-specific or domain-specific data. Extensions define the structure of data within the ext.{namespace} field. Agents declare which extensions they support in their agent card.", + "registry": { + "$ref": "/schemas/extensions/index.json", + "description": "Auto-generated registry of all available extensions with metadata" + }, + "meta": { + "$ref": "/schemas/extensions/extension-meta.json", + "description": "Schema that all extension files must follow. Defines valid_from, valid_until, and extension data structure." + }, + "schemas": {} } }, "usage": { diff --git a/static/schemas/source/protocols/adcp-extension.json b/static/schemas/source/protocols/adcp-extension.json index 6e3c070374..6c27ac7491 100644 --- a/static/schemas/source/protocols/adcp-extension.json +++ b/static/schemas/source/protocols/adcp-extension.json @@ -1,14 +1,14 @@ { "$schema": "http://json-schema.org/draft-07/schema#", "$id": "/schemas/protocols/adcp-extension.json", - "title": "AdCP Agent Card Extension", - "description": "Extension metadata for agent cards (MCP and A2A) declaring AdCP version and supported protocol domains", + "title": "AdCP Agent Card Extension Params", + "description": "Parameters for declaring AdCP support in agent discovery. For A2A, use in extensions[].params. For MCP, use in _meta['adcontextprotocol.org'].", "type": "object", "properties": { "adcp_version": { "type": "string", "pattern": "^\\d+\\.\\d+\\.\\d+$", - "description": "Semantic version of the AdCP specification this agent implements (e.g., '2.4.0')" + "description": "Semantic version of the AdCP specification this agent implements (e.g., '2.5.0'). Extension schemas are versioned along with the AdCP spec." }, "protocols_supported": { "type": "array", @@ -23,6 +23,16 @@ "minItems": 1, "uniqueItems": true, "description": "AdCP protocol domains supported by this agent. At least one must be specified." + }, + "extensions_supported": { + "type": "array", + "description": "Typed extensions this agent supports. Each extension has a formal schema in /schemas/extensions/. Extension version is determined by adcp_version.", + "items": { + "type": "string", + "pattern": "^[a-z][a-z0-9_]*$", + "description": "Extension namespace (e.g., 'sustainability'). Must be lowercase alphanumeric with underscores." + }, + "uniqueItems": true } }, "required": [ diff --git a/tests/extension-schemas.test.cjs b/tests/extension-schemas.test.cjs new file mode 100644 index 0000000000..cf27260202 --- /dev/null +++ b/tests/extension-schemas.test.cjs @@ -0,0 +1,445 @@ +#!/usr/bin/env node +/** + * Extension schema validation test suite + * Tests that the typed extension infrastructure is properly configured + */ + +const fs = require('fs'); +const path = require('path'); +const Ajv = require('ajv'); +const addFormats = require('ajv-formats'); + +const SCHEMA_BASE_DIR = path.join(__dirname, '../static/schemas/source'); +const EXTENSIONS_DIR = path.join(SCHEMA_BASE_DIR, 'extensions'); + +// Initialize AJV with formats and custom loader +const ajv = new Ajv({ + allErrors: true, + verbose: true, + strict: false, + loadSchema: loadExternalSchema +}); +addFormats(ajv); + +// Schema loader for resolving $ref +async function loadExternalSchema(uri) { + let relativePath; + if (uri.startsWith('/schemas/v1/')) { + relativePath = uri.replace('/schemas/v1/', ''); + } else if (uri.startsWith('/schemas/')) { + relativePath = uri.replace('/schemas/', ''); + } else { + throw new Error(`Cannot load external schema: ${uri}`); + } + + const schemaPath = path.join(SCHEMA_BASE_DIR, relativePath); + try { + const content = fs.readFileSync(schemaPath, 'utf8'); + return JSON.parse(content); + } catch (error) { + throw new Error(`Failed to load referenced schema ${uri}: ${error.message}`); + } +} + +let totalTests = 0; +let passedTests = 0; +let failedTests = 0; + +function log(message, type = 'info') { + const colors = { + info: '\x1b[0m', + success: '\x1b[32m', + error: '\x1b[31m', + warning: '\x1b[33m' + }; + console.log(`${colors[type]}${message}\x1b[0m`); +} + +async function test(description, testFn) { + totalTests++; + try { + const result = await testFn(); + if (result === true || result === undefined) { + log(`✅ ${description}`, 'success'); + passedTests++; + } else { + log(`❌ ${description}: ${result}`, 'error'); + failedTests++; + } + } catch (error) { + log(`❌ ${description}: ${error.message}`, 'error'); + if (error.errors) { + console.error('Validation errors:', JSON.stringify(error.errors, null, 2)); + } + failedTests++; + } +} + +// Cache for compiled schemas +const schemaCache = new Map(); + +async function loadAndCompileSchema(schemaPath) { + if (schemaCache.has(schemaPath)) { + return schemaCache.get(schemaPath); + } + + const schemaContent = fs.readFileSync(schemaPath, 'utf8'); + const schema = JSON.parse(schemaContent); + const validate = await ajv.compileAsync(schema); + + schemaCache.set(schemaPath, validate); + return validate; +} + +// Discover extension files (excluding index.json and extension-meta.json) +function discoverExtensionFiles() { + if (!fs.existsSync(EXTENSIONS_DIR)) { + return []; + } + + return fs.readdirSync(EXTENSIONS_DIR) + .filter(file => + file.endsWith('.json') && + file !== 'index.json' && + file !== 'extension-meta.json' + ) + .map(file => path.join(EXTENSIONS_DIR, file)); +} + +async function runTests() { + log('🧪 Starting Extension Schema Validation Tests'); + log('=============================================='); + + // Test 1: Extension directory exists + await test('Extension directory exists', async () => { + if (!fs.existsSync(EXTENSIONS_DIR)) { + throw new Error(`Extension directory not found: ${EXTENSIONS_DIR}`); + } + return true; + }); + + // Test 2: Extension index exists and is valid JSON + await test('Extension index exists and is valid JSON', async () => { + const indexPath = path.join(EXTENSIONS_DIR, 'index.json'); + if (!fs.existsSync(indexPath)) { + throw new Error('Extension index.json not found'); + } + const content = fs.readFileSync(indexPath, 'utf8'); + JSON.parse(content); // Will throw if invalid JSON + return true; + }); + + // Test 3: Extension index has proper structure + await test('Extension index has proper structure', async () => { + const indexPath = path.join(EXTENSIONS_DIR, 'index.json'); + const index = JSON.parse(fs.readFileSync(indexPath, 'utf8')); + + if (!index.$schema) { + throw new Error('Extension index missing $schema'); + } + if (!index.$id) { + throw new Error('Extension index missing $id'); + } + if (!index.title) { + throw new Error('Extension index missing title'); + } + if (typeof index.extensions !== 'object') { + throw new Error('Extension index missing extensions object'); + } + if (!index._generated) { + throw new Error('Extension index should have _generated: true marker'); + } + return true; + }); + + // Test 4: Extension meta schema exists and is valid + await test('Extension meta schema exists and is valid', async () => { + const metaPath = path.join(EXTENSIONS_DIR, 'extension-meta.json'); + if (!fs.existsSync(metaPath)) { + throw new Error('Extension extension-meta.json not found'); + } + const content = fs.readFileSync(metaPath, 'utf8'); + const meta = JSON.parse(content); + + // Verify it's a proper schema + if (!meta.$schema) { + throw new Error('Extension meta schema missing $schema'); + } + if (!meta.$id) { + throw new Error('Extension meta schema missing $id'); + } + if (!meta.properties.valid_from) { + throw new Error('Extension meta schema missing valid_from property'); + } + if (!meta.properties.valid_until) { + throw new Error('Extension meta schema missing valid_until property'); + } + return true; + }); + + // Test 5: Agent card extension schema supports extensions_supported field + await test('Agent card extension schema supports extensions_supported', async () => { + const validate = await loadAndCompileSchema( + path.join(SCHEMA_BASE_DIR, 'protocols/adcp-extension.json') + ); + + const validData = { + adcp_version: '2.5.0', + protocols_supported: ['media_buy'], + extensions_supported: ['sustainability', 'custom_vendor'] + }; + + const valid = validate(validData); + if (!valid) { + throw new Error(`Validation failed: ${JSON.stringify(validate.errors)}`); + } + return true; + }); + + // Test 6: Agent card validates without extensions_supported (optional field) + await test('Agent card validates without extensions_supported', async () => { + const validate = await loadAndCompileSchema( + path.join(SCHEMA_BASE_DIR, 'protocols/adcp-extension.json') + ); + + const validData = { + adcp_version: '2.5.0', + protocols_supported: ['media_buy', 'creative'] + }; + + const valid = validate(validData); + if (!valid) { + throw new Error(`Validation failed: ${JSON.stringify(validate.errors)}`); + } + return true; + }); + + // Test 7: Agent card rejects invalid extension namespace format + await test('Agent card rejects invalid extension namespace format', async () => { + const validate = await loadAndCompileSchema( + path.join(SCHEMA_BASE_DIR, 'protocols/adcp-extension.json') + ); + + const invalidData = { + adcp_version: '2.5.0', + protocols_supported: ['media_buy'], + extensions_supported: ['Invalid-Namespace'] // Must be lowercase + }; + + const valid = validate(invalidData); + if (valid) { + throw new Error('Should have rejected invalid namespace format'); + } + return true; + }); + + // Test 8: Product can include arbitrary extension data (untyped) + await test('Product validates with arbitrary extension data', async () => { + const validate = await loadAndCompileSchema( + path.join(SCHEMA_BASE_DIR, 'core/product.json') + ); + + const product = { + product_id: 'test_product', + name: 'Test Product', + description: 'Test description', + publisher_properties: [{ + publisher_domain: 'example.com', + selection_type: 'all' + }], + format_ids: [{ + agent_url: 'https://creative.adcontextprotocol.org', + id: 'display_300x250' + }], + delivery_type: 'guaranteed', + delivery_measurement: { + provider: 'Test Provider' + }, + pricing_options: [{ + is_fixed: true, + pricing_option_id: 'fixed_cpm', + pricing_model: 'cpm', + rate: 10.00, + currency: 'USD' + }], + ext: { + custom_vendor: { + some_field: 'some_value', + nested: { data: true } + }, + another_vendor: { + config: [1, 2, 3] + } + } + }; + + const valid = validate(product); + if (!valid) { + throw new Error(`Validation failed: ${JSON.stringify(validate.errors)}`); + } + return true; + }); + + // Test 9: Extension meta schema validates a sample extension + await test('Extension meta schema validates sample extension structure', async () => { + const validate = await loadAndCompileSchema( + path.join(EXTENSIONS_DIR, 'extension-meta.json') + ); + + const sampleExtension = { + $schema: 'http://json-schema.org/draft-07/schema#', + $id: '/schemas/extensions/sustainability.json', + title: 'Sustainability Extension', + description: 'Carbon footprint and green certification data', + valid_from: '2.5', + docs_url: 'https://adcontextprotocol.org/docs/extensions/sustainability', + type: 'object', + properties: { + carbon_kg_per_impression: { type: 'number' }, + certified_green: { type: 'boolean' } + } + }; + + const valid = validate(sampleExtension); + if (!valid) { + throw new Error(`Validation failed: ${JSON.stringify(validate.errors)}`); + } + return true; + }); + + // Test 10: Extension meta schema validates extension with valid_until + await test('Extension meta schema validates extension with valid_until', async () => { + const validate = await loadAndCompileSchema( + path.join(EXTENSIONS_DIR, 'extension-meta.json') + ); + + const sampleExtension = { + $schema: 'http://json-schema.org/draft-07/schema#', + $id: '/schemas/extensions/deprecated_feature.json', + title: 'Deprecated Feature Extension', + description: 'A feature that was deprecated in version 3.0', + valid_from: '2.0', + valid_until: '3.0', + type: 'object', + properties: { + legacy_field: { type: 'string' } + } + }; + + const valid = validate(sampleExtension); + if (!valid) { + throw new Error(`Validation failed: ${JSON.stringify(validate.errors)}`); + } + return true; + }); + + // Test 11: Extension meta schema rejects invalid valid_from format + await test('Extension meta schema rejects invalid valid_from format', async () => { + const validate = await loadAndCompileSchema( + path.join(EXTENSIONS_DIR, 'extension-meta.json') + ); + + const invalidExtension = { + $schema: 'http://json-schema.org/draft-07/schema#', + $id: '/schemas/extensions/bad_version.json', + title: 'Bad Version Extension', + description: 'Has invalid version format', + valid_from: '2.5.0', // Should be "2.5" not "2.5.0" + type: 'object', + properties: {} + }; + + const valid = validate(invalidExtension); + if (valid) { + throw new Error('Should have rejected invalid valid_from format (semver patch level not allowed)'); + } + return true; + }); + + // Test 12: Extension meta schema rejects invalid $id pattern + await test('Extension meta schema rejects invalid $id pattern', async () => { + const validate = await loadAndCompileSchema( + path.join(EXTENSIONS_DIR, 'extension-meta.json') + ); + + const invalidExtension = { + $schema: 'http://json-schema.org/draft-07/schema#', + $id: '/schemas/core/not_an_extension.json', // Wrong path + title: 'Wrong Path Extension', + description: 'Has invalid $id path', + valid_from: '2.5', + type: 'object', + properties: {} + }; + + const valid = validate(invalidExtension); + if (valid) { + throw new Error('Should have rejected invalid $id pattern'); + } + return true; + }); + + // Test 13: Reserved namespaces should be rejected by build script validation + await test('Reserved namespaces are documented', async () => { + // These namespaces are reserved in scripts/build-schemas.cjs + const RESERVED_NAMESPACES = ['adcp', 'core', 'protocol', 'schema', 'meta', 'ext', 'context']; + + // Verify none of the reserved namespaces exist as extension files + for (const reserved of RESERVED_NAMESPACES) { + const reservedPath = path.join(EXTENSIONS_DIR, `${reserved}.json`); + if (fs.existsSync(reservedPath)) { + throw new Error(`Reserved namespace "${reserved}" should not exist as an extension file`); + } + } + return true; + }); + + // Test 14: Discovered extensions validate against meta schema + const extensionFiles = discoverExtensionFiles(); + if (extensionFiles.length > 0) { + for (const extensionPath of extensionFiles) { + const filename = path.basename(extensionPath); + await test(`Extension file ${filename} validates against meta schema`, async () => { + const validate = await loadAndCompileSchema( + path.join(EXTENSIONS_DIR, 'extension-meta.json') + ); + + const content = fs.readFileSync(extensionPath, 'utf8'); + const extension = JSON.parse(content); + + const valid = validate(extension); + if (!valid) { + throw new Error(`Validation failed: ${JSON.stringify(validate.errors)}`); + } + return true; + }); + } + } else { + await test('No extension files to validate (registry is empty)', async () => { + log(' ℹ️ No extension files found - this is expected for initial setup', 'warning'); + return true; + }); + } + + // Summary + log(''); + log('=============================================='); + log(`Tests completed: ${totalTests}`); + log(`✅ Passed: ${passedTests}`, 'success'); + if (failedTests > 0) { + log(`❌ Failed: ${failedTests}`, 'error'); + log(''); + process.exit(1); + } else { + log(''); + log('🎉 All extension schema tests passed!', 'success'); + process.exit(0); + } +} + +// Run tests +runTests().catch(error => { + log(`Fatal error: ${error.message}`, 'error'); + console.error(error); + process.exit(1); +}); From 5cd83b819f6bbac049c3429c5ec1ac8a3b65d431 Mon Sep 17 00:00:00 2001 From: Brian O'Kelley Date: Mon, 12 Jan 2026 15:54:09 -0500 Subject: [PATCH 16/34] Add Property Governance Protocol for AdCP 3.0 (#588) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add Property Governance Protocol for AdCP 3.0 This introduces a stateful property list management model for governance agents: ## Key Concepts - **Property Lists**: Managed resources combining base property sets with dynamic filters - **Feature Discovery**: Agents advertise scoring capabilities via `list_property_features` - **Brand Manifests**: Buyers describe their brand identity; agents apply appropriate rules - **Discriminated Unions**: `base_properties` uses `selection_type` discriminator for type safety ## Design Principles - **Scores are internal**: Governance agents filter properties; raw scores never leave the agent - **Setup-time, not bid-time**: Lists resolved during campaign planning, cached for real-time - **Identifiers-only responses**: `get_property_list` returns identifiers, not full property objects - **Notification webhooks**: Webhooks provide summary; recipients call `get_property_list` to refresh ## Schemas Added - Property list CRUD operations (create, update, get, list, delete) - Property list filters with explicit logic (`countries_all`, `channels_any`, `feature_requirements`) - Feature requirements for quantitative (`min_value`/`max_value`) and categorical (`allowed_values`) - Base property source with discriminated union (publisher_tags, publisher_ids, identifiers) - Webhook notification schema - Core identifier schema for reuse ## Documentation - Governance Protocol overview - Property Governance specification - Task reference for all CRUD operations - Brand Standards placeholder 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Add changeset for Property Governance Protocol 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Use empty changeset for draft 3.0 proposal No version bump needed for draft/proposal specs. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Address review feedback on Property Governance Protocol Schema fixes: - Add methodology_url (required) and methodology_version to property-feature-definition - Add signature field (required) to webhook schema for security - Make countries_all and channels_any required in property-list-filters - Move auth_token from get_property_list to create_property_list response Documentation fixes: - Add terminology note: Orchestrator = Buyer Agent - Update examples to show auth_token in create response only - Add note that auth_token is only returned at creation time 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Add validate_property_delivery task for post-campaign compliance validation Introduces the "what I wanted vs what I got" validation concept: - validate_property_delivery task validates delivery records against property lists - Three statuses: compliant, non_compliant, unknown - Unknown records are valid (detection gaps shouldn't penalize compliance) - Compliance rate excludes unknown impressions from calculation - Batch support up to 10,000 records per request New schemas: - delivery-record.json: Input record with identifier + impressions - validation-result.json: Per-record validation result with status and violations - validate-property-delivery-request.json: Request payload - validate-property-delivery-response.json: Response with summary and per-record results 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Add supply path authorization to validate_property_delivery Extends validate_property_delivery to validate sales agent authorization: - Add optional sales_agent_url to delivery records - Check if sales agent is listed in publisher's adagents.json - Return authorization status (authorized/unauthorized/unknown) per record - Add authorization_summary with aggregate stats and authorization_rate - Two independent checks: property compliance + supply path authorization New schema: - authorization-result.json: Per-record authorization validation result Authorization uses same "unknown excludes from rate" pattern as property compliance - you cannot penalize for detection gaps or unreachable files. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Simplify validation response: raw counts + optional feature details Changes: - Remove compliance_rate and authorization_rate from response schemas - Return raw counts only (1.2M verified, 0.8M unknown, 0.3M invalid) - Consumers calculate rates as needed, excluding unknowns from denominator - Add optional feature_id and requirement to violation objects - For feature_failed violations, shows which feature and what threshold failed - Helps debugging why a property was marked non-compliant 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Split unknown into unmodeled/unidentified, add optional aggregate metrics - Split "unknown" status into two distinct statuses: - unmodeled: identifier recognized but agent has no data (e.g., property too new) - unidentified: identifier type not resolvable (e.g., detection failed) - Add optional aggregate field for computed metrics: - score, grade, label fields for agent-specific measurements - methodology_url for transparency - Update summary to track both unmodeled and unidentified separately - Update documentation with new statuses and aggregate concept Inspired by Scope3's inventory_coverage (modeled/unmodeled) pattern. The distinction helps identify whether gaps are in data coverage vs identifier resolution. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Fix include_compliant description to reference new statuses Updated the description to list non_compliant, unmodeled, and unidentified (instead of the old "unknown" status). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Move authorized-properties doc to Governance Protocol section - Moved authorized-properties.mdx from media-buy/capability-discovery to governance/property (renamed to "Understanding Authorization") - Added validate_property_delivery task to navigation - Navigation now shows conceptual explainer before tech spec 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Fix broken links to authorized-properties after move Updated links in media-buy docs to point to new location in governance/property section. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Add property_list filtering to get_products for 2.6.x - Add optional property_list parameter to get_products request schema - Add property_list_applied response field to indicate filtering status - Update get_products docs with new parameter, response field, and usage example - Mark changeset as minor for 2.6.x release 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Add governance overview enhancements for working group alignment - Change banner from Info to Warning for draft status - Add mission statement for governance protocols - Add Working Group Areas table mapping to protocol domains - Add Prompt-Based Policies section for natural language policy support 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Fix broken links in v2.6-rc docs after authorized-properties move Update links from /docs/media-buy/capability-discovery/adagents and /docs/media-buy/capability-discovery/authorized-properties to their new locations in /docs/governance/property/ 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Add get_property_features task and property_features discovery - Add get_property_features task schemas for governance agents to return property certification/measurement data (carbon scores, TAG certified, etc.) - Support two request modes: explicit property list or publisher discovery - Add publisher_domain, property_types, property_tags filtering for discovery - Add property_features field to adagents.json for feature provider discovery - Rename from governance_agents to property_features for flexibility 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Add filter semantics for geographic and channel compliance Clarifies what "compliant in a country" means for property list filters: - Refers to user location (where impressions are delivered) - NOT publisher headquarters, server hosting, or incorporation country - Requires regulatory compliance, ad delivery capability, and valid consent Also clarifies channel filter semantics (technical capability, availability, quality standards) and adds cross-references between docs and schema. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Revert filter semantics changes The Filter Semantics section overstated the meaning of countries_all - it's about whether the agent has feature data for properties in that country, not about legal compliance. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Add if_not_covered handling and standardize on 'covered' terminology - Add if_not_covered field to feature-requirement.json (exclude|include) - Add coverage_gaps to get-property-list-response.json for transparency - Change 'unmodeled' to 'not_covered' throughout for consistency: - validation-result.json status enum - validate-property-delivery-response.json summary fields - specification.mdx and validate_property_delivery.mdx documentation - Document coverage handling in property_lists.mdx This allows callers to specify how missing feature data should be handled (strict vs lenient enforcement) and provides visibility into which properties were included despite coverage gaps. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Clarify countries_all semantics: feature data, not compliance Remove "compliant" language from countries_all descriptions to avoid confusion with legal/regulatory compliance. The field means "property must have feature data for these countries" - same semantics as content standards PR 621 ("standards apply in these countries"). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --------- Co-authored-by: Claude Opus 4.5 --- .changeset/property-governance-protocol.md | 9 + docs.json | 37 +- docs/governance/brand-standards/index.mdx | 90 +++ docs/governance/index.mdx | 187 +++++ .../property}/adagents.mdx | 4 +- .../property}/authorized-properties.mdx | 7 +- docs/governance/property/index.mdx | 227 ++++++ docs/governance/property/specification.mdx | 611 +++++++++++++++ docs/governance/property/tasks/index.mdx | 153 ++++ .../property/tasks/list_property_features.mdx | 235 ++++++ .../property/tasks/property_lists.mdx | 701 ++++++++++++++++++ .../tasks/validate_property_delivery.mdx | 402 ++++++++++ docs/media-buy/capability-discovery/index.mdx | 6 +- docs/media-buy/index.mdx | 2 +- .../media-buy/task-reference/get_products.mdx | 81 ++ .../list_authorized_properties.mdx | 2 +- docs/reference/implementor-faq.mdx | 2 +- docs/reference/roadmap.mdx | 4 +- package-lock.json | 4 +- static/schemas/source/adagents.json | 92 +++ static/schemas/source/core/identifier.json | 19 + .../source/core/property-list-ref.json | 25 + static/schemas/source/enums/adcp-domain.json | 11 +- static/schemas/source/enums/task-type.json | 18 +- static/schemas/source/index.json | 111 ++- .../media-buy/get-products-request.json | 4 + .../media-buy/get-products-response.json | 4 + .../source/property/authorization-result.json | 41 + .../source/property/base-property-source.json | 87 +++ .../create-property-list-request.json | 40 + .../create-property-list-response.json | 22 + .../delete-property-list-request.json | 21 + .../delete-property-list-response.json | 22 + .../source/property/delivery-record.json | 32 + .../source/property/feature-requirement.json | 34 + .../get-property-features-request.json | 68 ++ .../get-property-features-response.json | 28 + .../property/get-property-list-request.json | 35 + .../property/get-property-list-response.json | 68 ++ .../list-property-features-request.json | 27 + .../list-property-features-response.json | 21 + .../property/list-property-lists-request.json | 34 + .../list-property-lists-response.json | 44 ++ .../source/property/property-error.json | 31 + .../property/property-feature-definition.json | 84 +++ .../property/property-feature-result.json | 43 ++ .../property/property-feature-value.json | 51 ++ .../source/property/property-feature.json | 23 + .../property-list-changed-webhook.json | 60 ++ .../property/property-list-filters.json | 47 ++ .../source/property/property-list.json | 67 ++ .../update-property-list-request.json | 49 ++ .../update-property-list-response.json | 18 + .../validate-property-delivery-request.json | 32 + .../validate-property-delivery-response.json | 167 +++++ .../source/property/validation-result.json | 79 ++ .../authorized-properties.mdx | 4 +- .../media-buy/capability-discovery/index.mdx | 6 +- v2.6-rc/docs/media-buy/index.mdx | 2 +- .../list_authorized_properties.mdx | 2 +- v2.6-rc/docs/reference/implementor-faq.mdx | 2 +- 61 files changed, 4400 insertions(+), 39 deletions(-) create mode 100644 .changeset/property-governance-protocol.md create mode 100644 docs/governance/brand-standards/index.mdx create mode 100644 docs/governance/index.mdx rename docs/{media-buy/capability-discovery => governance/property}/adagents.mdx (98%) rename docs/{media-buy/capability-discovery => governance/property}/authorized-properties.mdx (97%) create mode 100644 docs/governance/property/index.mdx create mode 100644 docs/governance/property/specification.mdx create mode 100644 docs/governance/property/tasks/index.mdx create mode 100644 docs/governance/property/tasks/list_property_features.mdx create mode 100644 docs/governance/property/tasks/property_lists.mdx create mode 100644 docs/governance/property/tasks/validate_property_delivery.mdx create mode 100644 static/schemas/source/core/identifier.json create mode 100644 static/schemas/source/core/property-list-ref.json create mode 100644 static/schemas/source/property/authorization-result.json create mode 100644 static/schemas/source/property/base-property-source.json create mode 100644 static/schemas/source/property/create-property-list-request.json create mode 100644 static/schemas/source/property/create-property-list-response.json create mode 100644 static/schemas/source/property/delete-property-list-request.json create mode 100644 static/schemas/source/property/delete-property-list-response.json create mode 100644 static/schemas/source/property/delivery-record.json create mode 100644 static/schemas/source/property/feature-requirement.json create mode 100644 static/schemas/source/property/get-property-features-request.json create mode 100644 static/schemas/source/property/get-property-features-response.json create mode 100644 static/schemas/source/property/get-property-list-request.json create mode 100644 static/schemas/source/property/get-property-list-response.json create mode 100644 static/schemas/source/property/list-property-features-request.json create mode 100644 static/schemas/source/property/list-property-features-response.json create mode 100644 static/schemas/source/property/list-property-lists-request.json create mode 100644 static/schemas/source/property/list-property-lists-response.json create mode 100644 static/schemas/source/property/property-error.json create mode 100644 static/schemas/source/property/property-feature-definition.json create mode 100644 static/schemas/source/property/property-feature-result.json create mode 100644 static/schemas/source/property/property-feature-value.json create mode 100644 static/schemas/source/property/property-feature.json create mode 100644 static/schemas/source/property/property-list-changed-webhook.json create mode 100644 static/schemas/source/property/property-list-filters.json create mode 100644 static/schemas/source/property/property-list.json create mode 100644 static/schemas/source/property/update-property-list-request.json create mode 100644 static/schemas/source/property/update-property-list-response.json create mode 100644 static/schemas/source/property/validate-property-delivery-request.json create mode 100644 static/schemas/source/property/validate-property-delivery-response.json create mode 100644 static/schemas/source/property/validation-result.json diff --git a/.changeset/property-governance-protocol.md b/.changeset/property-governance-protocol.md new file mode 100644 index 0000000000..882945edce --- /dev/null +++ b/.changeset/property-governance-protocol.md @@ -0,0 +1,9 @@ +--- +"adcontextprotocol": minor +--- + +Add Property Governance Protocol support to get_products + +- Add optional `property_list` parameter to get_products request for filtering products by property list +- Add `property_list_applied` response field to indicate whether filtering was applied +- Enables buyers to pass property lists from governance agents to sales agents for compliant inventory discovery diff --git a/docs.json b/docs.json index cf2262d30a..ca5b1d84a3 100644 --- a/docs.json +++ b/docs.json @@ -80,13 +80,6 @@ "docs/protocols/envelope-examples" ] }, - { - "group": "adagents.json", - "pages": [ - "docs/media-buy/capability-discovery/adagents", - "docs/media-buy/capability-discovery/authorized-properties" - ] - }, { "group": "Signals Protocol", "pages": [ @@ -101,6 +94,36 @@ } ] }, + { + "group": "Governance Protocol [3.0]", + "pages": [ + "docs/governance/index", + { + "group": "Property Governance", + "pages": [ + "docs/governance/property/index", + "docs/governance/property/specification", + "docs/governance/property/authorized-properties", + "docs/governance/property/adagents", + { + "group": "Tasks", + "pages": [ + "docs/governance/property/tasks/index", + "docs/governance/property/tasks/list_property_features", + "docs/governance/property/tasks/property_lists", + "docs/governance/property/tasks/validate_property_delivery" + ] + } + ] + }, + { + "group": "Brand Standards", + "pages": [ + "docs/governance/brand-standards/index" + ] + } + ] + }, { "group": "Curation Protocol", "pages": [ diff --git a/docs/governance/brand-standards/index.mdx b/docs/governance/brand-standards/index.mdx new file mode 100644 index 0000000000..15a738adc0 --- /dev/null +++ b/docs/governance/brand-standards/index.mdx @@ -0,0 +1,90 @@ +--- +sidebar_position: 1 +title: Brand Standards +--- + + +**AdCP 3.0 Proposal** - This protocol is under development for AdCP 3.0. Feedback welcome via [GitHub Discussions](https://github.com/adcontextprotocol/adcp/discussions). + + +Brand Standards governance enables buyers to declare brand requirements that governance agents use to automatically apply appropriate rules across advertising workflows. + +## Overview + +Brand Standards addresses three concerns: + +| Concern | Description | Mechanism | +|---------|-------------|-----------| +| **Brand Identity** | Who is the advertiser? | Brand manifest declarations | +| **Creative Guidelines** | What can the brand show? | Creative constraints and policies | +| **Audience Constraints** | Who should see the ads? | Industry-specific targeting rules | + +## Brand Manifest + +The brand manifest is the core declaration that buyers provide to governance agents: + +```json +{ + "brand_manifest": { + "brand_name": "ToyBrand", + "industry": "toys", + "target_audience": "children_under_13", + "prohibited_categories": ["gambling", "alcohol", "tobacco"], + "creative_guidelines": { + "max_animation_duration": 15, + "require_accessibility": true + } + } +} +``` + +When governance agents receive a brand manifest, they automatically apply: + +- **Regulatory compliance**: COPPA for children's brands, GDPR consent requirements +- **Content filtering**: Block categories inappropriate for the brand's audience +- **Creative validation**: Enforce brand-specific creative guidelines + +## Integration with Property Governance + +Brand manifests work alongside property lists. When creating a property list, include the brand manifest to get automatic rule application: + +```json +{ + "tool": "create_property_list", + "arguments": { + "name": "ToyBrand Q1 Properties", + "base_properties": [ + { + "selection_type": "publisher_tags", + "publisher_domain": "kidsmedia.com", + "tags": ["kids_family", "educational"] + } + ], + "filters": { + "countries_all": ["US"], + "channels_any": ["display", "video"], + "feature_requirements": [ + { "feature_id": "brand_safety", "min_value": 90, "max_value": 100 } + ] + }, + "brand_manifest": { + "brand_name": "ToyBrand", + "industry": "toys", + "target_audience": "children_under_13" + } + } +} +``` + +The governance agent uses the brand manifest to apply COPPA requirements, filter out non-child-safe properties, and enforce relevant industry rules. + +## Coming Soon + +Detailed specification and task definitions for Brand Standards governance are under development. Key planned features: + +- **Brand manifest validation**: Verify manifest completeness and consistency +- **Industry rule sets**: Pre-defined rules for common industries (toys, alcohol, pharmaceuticals, finance) +- **Creative compliance**: Validate creatives against brand guidelines +- **Audience verification**: Ensure targeting complies with brand audience constraints + +See the [Governance Protocol overview](/docs/governance/index) for the broader context of how Brand Standards fits into AdCP governance. diff --git a/docs/governance/index.mdx b/docs/governance/index.mdx new file mode 100644 index 0000000000..f08e368f2d --- /dev/null +++ b/docs/governance/index.mdx @@ -0,0 +1,187 @@ +--- +sidebar_position: 1 +title: Governance Protocol +--- + + +**Draft for AdCP 3.0** - These governance protocols are under active development by the AAO Governance Working Group. Feedback welcome via [GitHub Discussions](https://github.com/adcontextprotocol/adcp/discussions). + + +The Governance Protocol provides standardized mechanisms for compliance, brand safety, and quality control across advertising workflows. It enables specialized agents to evaluate, filter, and score advertising entities against configurable criteria. + +## Mission + +> Define and operate transparent, privacy-safe, brand-suitable campaign governance that encodes human heuristics in open protocol objects, making campaigns easy to launch, safe to scale, and measurable against verifiable outcomes for buyers, sellers, and auditors. + +## Protocol Domains + +The Governance Protocol covers four distinct governance domains: + +| Domain | What It Governs | Key Mechanisms | +|--------|-----------------|----------------| +| **[Property Governance](/docs/governance/property/index)** | Where ads can run | Property lists, compliance filtering, adagents.json authorization | +| **[Brand Standards](/docs/governance/brand-standards/index)** | Brand requirements | Brand manifests, creative guidelines, audience constraints | +| **Creative Governance** | What creatives are compliant | Format validation, content moderation, accessibility | +| **Campaign Governance** | What can be bought | Budget controls, approval workflows, policy compliance | + +Each domain has specialized governance agents that provide data, filtering, and scoring capabilities. + +## Working Group Areas + +The AAO Governance Working Group is developing standards across six areas that inform these protocols: + +| Area | Focus | Protocol Impact | +|------|-------|-----------------| +| Brand Safety & Suitability | Safe, appropriate ad contexts | Property Governance, Content filtering | +| Brand Manifesto & Standards Library | Machine-readable brand policies | Brand Standards | +| Creative Standards & Validation | Technical and ethical creative criteria | Creative Governance | +| Process & Human Oversight | Human-in-the-loop checkpoints | All protocols | +| Regulatory & Compliance | Legal and regional frameworks | All protocols | +| Measurement & Verification | Proving compliance | All protocols | + +## Architecture + +Governance agents operate across the **full campaign lifecycle**: + +- **Setup time**: Configure property lists, brand requirements, and compliance rules +- **Real-time**: Influence bid-time decisions through cached rules and scoring +- **Post-bid**: Measurement, verification, and reporting on compliance + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ BUYER AGENT │ +│ - Aggregates governance from specialized agents │ +│ - Issues auth_tokens for sellers to access governance data │ +│ - Source of truth for compliant lists and brand requirements │ +└───────────────────────────┬─────────────────────────────────────────────┘ + │ create_property_list, webhooks + ┌───────────────────┼───────────────────┐ + ▼ ▼ ▼ +┌───────────────┐ ┌───────────────┐ ┌───────────────┐ +│ Consent Agent │ │ Scope3 Agent │ │ Brand Safety │ +│ (Compliance) │ │ │ │ Agent │ +├───────────────┤ ├───────────────┤ ├───────────────┤ +│ consent_qual │ │ carbon_score │ │ content_cat │ +│ tcf_version │ │ climate_risk │ │ brand_risk │ +│ coppa_cert │ │ green_host │ │ sentiment │ +└───────────────┘ └───────────────┘ └───────────────┘ + │ + │ get_property_list (with auth_token) + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ SELLER AGENT (DSP/SSP) │ +│ - Caches resolved property lists for bid-time decisions │ +│ - Receives updates via webhooks when lists change │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +## Common Patterns + +### Feature Discovery + +All governance agents advertise their capabilities via discovery tasks: + +```json +{ + "tool": "list_property_features", + "arguments": {} +} +``` + +Response: +```json +{ + "features": [ + { "feature_id": "consent_quality", "type": "quantitative", "range": { "min": 0, "max": 100 } }, + { "feature_id": "coppa_certified", "type": "binary" }, + { "feature_id": "carbon_score", "type": "quantitative", "range": { "min": 0, "max": 100 } } + ] +} +``` + +### Brand Manifest + +Buyers declare their brand identity, and governance agents automatically apply appropriate rules: + +```json +{ + "brand_manifest": { + "brand_name": "ToyBrand", + "industry": "toys", + "target_audience": "children_under_13" + } +} +``` + +When a governance agent sees this manifest, it automatically applies COPPA requirements, content filtering for children's brands, and other industry-specific rules. + +### Prompt-Based Policies + +Governance protocols support **natural language prompts** for policy definitions rather than rigid keyword lists: + +```json +{ + "policy": "Avoid content about violence, controversial politics, or adult themes. Sports news is excellent. Entertainment is generally acceptable.", + "exclusions_prompt": "Block content containing hate speech, illegal activities, or ongoing litigation against our company." +} +``` + +This enables AI-powered verification agents to understand context and nuance. + +### Webhook Notifications + +Governance agents notify subscribers when evaluations change: + +```json +{ + "webhook_url": "https://buyer.example.com/webhooks/list-changed", + "events": ["list_updated", "property_removed", "score_changed"] +} +``` + +## Integration with Media Buy + +The Media Buy Protocol consumes governance data at multiple stages: + +- **Product discovery**: Pass `property_list_ref` to `get_products` to filter inventory +- **Media buy creation**: Reference property lists to constrain where ads can run +- **Authorization**: adagents.json validates agent authority to sell properties + +```json +{ + "tool": "get_products", + "arguments": { + "brief": "UK video inventory for Q1", + "property_list_ref": { + "agent_url": "https://buyer-agent.example.com", + "list_id": "pl_q1_uk_premium", + "auth_token": "..." + } + } +} +``` + +## Getting Started + +**Buyers:** +1. Subscribe to governance agents for property data and brand safety +2. Create property lists with filters and brand manifests +3. Aggregate results into final compliant lists +4. Share references with sellers (with auth tokens) + +**Governance Agent Implementers:** +1. Implement feature discovery tasks (`list_property_features`, etc.) +2. Implement stateful list management (CRUD operations) +3. Support webhooks to notify when evaluations change +4. See the [Property Protocol Specification](/docs/governance/property/specification) for detailed implementation guidance + +## Protocol Sections + + + + Control where ads can run with property lists, compliance filtering, and publisher authorization via adagents.json. + + + Define brand requirements including creative guidelines, audience constraints, and industry-specific rules. + + diff --git a/docs/media-buy/capability-discovery/adagents.mdx b/docs/governance/property/adagents.mdx similarity index 98% rename from docs/media-buy/capability-discovery/adagents.mdx rename to docs/governance/property/adagents.mdx index 442dee1805..2732d1d8f1 100644 --- a/docs/media-buy/capability-discovery/adagents.mdx +++ b/docs/governance/property/adagents.mdx @@ -1,9 +1,9 @@ --- -sidebar_position: 8 +sidebar_position: 3 title: adagents.json Tech Spec --- -The `adagents.json` file provides a standardized way for publishers to declare which sales agents are authorized to sell their advertising inventory. This specification addresses authorization transparency and helps prevent unauthorized reselling of publisher inventory. +The `adagents.json` file provides a standardized way for publishers to declare their properties and authorize sales agents. This is the foundation of Property Governance - it defines what properties exist and who can sell them. **[AdAgents.json Builder](https://adcontextprotocol.org/adagents)** - Validate existing files or create new ones with guided validation diff --git a/docs/media-buy/capability-discovery/authorized-properties.mdx b/docs/governance/property/authorized-properties.mdx similarity index 97% rename from docs/media-buy/capability-discovery/authorized-properties.mdx rename to docs/governance/property/authorized-properties.mdx index 11d72b671c..37981ec9e5 100644 --- a/docs/media-buy/capability-discovery/authorized-properties.mdx +++ b/docs/governance/property/authorized-properties.mdx @@ -1,5 +1,6 @@ --- -title: Authorized Properties +sidebar_position: 2.5 +title: Understanding Authorization description: Understanding property authorization in AdCP - preventing unauthorized resale and validating sales agent relationships keywords: [authorized properties, adagents.json, unauthorized resale, ads.txt, sales agent authorization, property validation] --- @@ -268,11 +269,11 @@ For complete technical details on implementing the `adagents.json` file format, - Validation code examples and error handling - Security considerations and best practices -See the **[adagents.json Tech Spec](/docs/media-buy/capability-discovery/adagents)** for complete implementation guidance. +See the **[adagents.json Tech Spec](/docs/governance/property/adagents)** for complete implementation guidance. ## Related Documentation - **[`list_authorized_properties`](/docs/media-buy/task-reference/list_authorized_properties)** - API reference for property discovery - **[Product Discovery](/docs/media-buy/product-discovery/)** - How authorization integrates with product discovery - **[Properties Schema](https://adcontextprotocol.org/schemas/v2/core/property.json)** - Technical property data model -- **[adagents.json Tech Spec](/docs/media-buy/capability-discovery/adagents)** - Complete `adagents.json` implementation guide \ No newline at end of file +- **[adagents.json Tech Spec](/docs/governance/property/adagents)** - Complete `adagents.json` implementation guide \ No newline at end of file diff --git a/docs/governance/property/index.mdx b/docs/governance/property/index.mdx new file mode 100644 index 0000000000..d4f8468777 --- /dev/null +++ b/docs/governance/property/index.mdx @@ -0,0 +1,227 @@ +--- +sidebar_position: 1 +title: Overview +--- + + +**AdCP 3.0 Proposal** - This protocol is under development for AdCP 3.0. Feedback welcome via [GitHub Discussions](https://github.com/adcontextprotocol/adcp/discussions). + + +Property Governance standardizes how advertising properties (websites, apps, CTV, podcasts, billboards) are identified, authorized, enriched with data, and selected for campaigns. + +## Overview + +Property Governance addresses four distinct concerns: + +| Concern | Question | Owner | Mechanism | +|---------|----------|-------|-----------| +| **Property Identity** | What properties exist? | Publishers | `adagents.json` properties array | +| **Sales Authorization** | Who can sell this property? | Publishers | `adagents.json` authorized_agents | +| **Property Data** | What do we know about this property? | Data providers | Governance agents via `list_property_features` | +| **Property Selection** | Which properties meet my requirements? | Buyers | Property lists with filters | + +The first two are **publisher-side declarations** via adagents.json. The last two are **buyer-side operations** that consume property data from governance agents. + +## Publisher Side: adagents.json + +Publishers declare their properties and authorize sales agents via `/.well-known/adagents.json`: + +```json +{ + "$schema": "https://adcontextprotocol.org/schemas/v2/adagents.json", + "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"] + } + ] +} +``` + +See the [adagents.json Tech Spec](/docs/governance/property/adagents) for complete documentation. + +## Buyer Side: Property Data and Selection + +### Property Data Providers + +Governance agents provide data about properties - compliance scores, brand safety ratings, sustainability metrics, etc. They advertise their capabilities via `list_property_features`: + +```json +{ + "features": [ + { "feature_id": "consent_quality", "type": "quantitative", "range": { "min": 0, "max": 100 } }, + { "feature_id": "coppa_certified", "type": "binary" }, + { "feature_id": "carbon_score", "type": "quantitative", "range": { "min": 0, "max": 100 } } + ] +} +``` + +Buyers send property lists to these agents, and the agents filter and score the properties based on their specialized data. Different agents specialize in different data: + +- **Compliance vendors** (data integrity, consent quality) +- **Brand safety providers** (content classification, risk scoring) +- **Quality measurement** (viewability, fraud detection) +- **Sustainability providers** (carbon scoring, green hosting) + +### Property Selection via Governance Agents + +Buyers create **property lists on governance agents** - the agents manage these lists and apply their filtering logic: + +```json +{ + "tool": "create_property_list", + "arguments": { + "name": "Q1 Campaign - UK Premium", + "base_properties": [ + { + "selection_type": "publisher_tags", + "publisher_domain": "raptive.com", + "tags": ["premium_news"] + } + ], + "filters": { + "countries_all": ["UK"], + "channels_any": ["display", "video"], + "feature_requirements": [ + { "feature_id": "consent_quality", "min_value": 85, "max_value": 100 } + ] + }, + "brand_manifest": { + "brand_name": "ToyBrand", + "industry": "toys", + "target_audience": "children_under_13" + } + } +} +``` + +When you provide a brand manifest, governance agents automatically apply appropriate rules (COPPA for children's brands, content filtering based on industry, etc.). + +A buyer agent typically works with **multiple governance agents** (consent, brand safety, sustainability) and aggregates/intersects their results into a final compliant list. + +## How It Fits Together + +```mermaid +flowchart TB + subgraph Buyer["BUYER AGENT"] + B1[Source of truth for compliant list] + B2[Aggregates results from specialized agents] + B3[Issues auth_tokens for sellers] + end + + subgraph Governance["GOVERNANCE AGENTS"] + CA["Consent Agent
consent_quality
tcf_version
coppa_certified"] + S3["Scope3 Agent
carbon_score
climate_risk
green_hosting"] + BS["Brand Safety Agent
content_category
brand_risk
sentiment"] + end + + subgraph Seller["SELLER AGENT (DSP/SSP)"] + SE1[Caches resolved property lists] + SE2[Uses cached lists for bid-time decisions] + end + + Buyer -->|create_property_list + webhooks| CA + Buyer -->|create_property_list + webhooks| S3 + Buyer -->|create_property_list + webhooks| BS + + Buyer -->|get_property_list with auth_token| Seller +``` + +## Sharing Property Lists with Sellers + +Once a buyer has a compliant property list, they share it with sellers: + +1. **Get a list reference**: The buyer agent exposes the list via `get_property_list` +2. **Issue an auth token**: The buyer generates a token that authorizes access to the list +3. **Pass to seller**: Include `property_list_ref` with `auth_token` in product discovery or media buy requests +4. **Seller caches locally**: Sellers fetch and cache the resolved list for bid-time decisions +5. **Webhooks for updates**: When the list changes, sellers are notified to refresh their cache + +```json +{ + "property_list_ref": { + "agent_url": "https://buyer-agent.example.com", + "list_id": "pl_q1_uk_premium", + "auth_token": "eyJhbGciOiJIUzI1NiIs..." + } +} +``` + +Sellers use this reference in `get_products` to filter available inventory: + +```json +{ + "tool": "get_products", + "arguments": { + "brief": "UK video inventory for Q1", + "property_list_ref": { + "agent_url": "https://buyer-agent.example.com", + "list_id": "pl_q1_uk_premium", + "auth_token": "..." + } + } +} +``` + +## Relationship to Other Protocols + +### Property Governance + Media Buy + +The Media Buy Protocol consumes property lists at multiple stages: + +- **Product discovery**: Pass `property_list_ref` to `get_products` to filter inventory to compliant properties +- **Media buy creation**: Reference property lists to constrain where ads can run +- **Authorization**: adagents.json validates agent authority to sell + +### Property Governance + Signals + +Both protocols operate on properties but serve different purposes: + +| Signals Protocol | Property Governance | +|------------------|---------------------| +| Audience/contextual data | Property metadata and compliance | +| "Who should see this ad?" | "Where can this ad run?" | +| Signal activation | Property filtering | + +## Tasks + +### Discovery + +- **[list_property_features](/docs/governance/property/tasks/list_property_features)**: Discover what data a governance agent can provide about properties + +### Property List Management + +- **[create_property_list](/docs/governance/property/tasks/property_lists#create_property_list)**: Create a new property list on a governance agent +- **[get_property_list](/docs/governance/property/tasks/property_lists#get_property_list)**: Retrieve resolved properties (with caching guidance) +- **[update_property_list](/docs/governance/property/tasks/property_lists#update_property_list)**: Modify filters or base properties +- **[delete_property_list](/docs/governance/property/tasks/property_lists#delete_property_list)**: Remove a property list + +## Getting Started + +**Publishers:** +1. Create `/.well-known/adagents.json` with property definitions +2. Authorize sales agents for your properties + +**Buyers:** +1. Subscribe to governance agents for property data +2. Create property lists on each governance agent with filters and brand manifests +3. Aggregate results into a final compliant list +4. Share property list references with sellers (with auth tokens) + +**Governance Agent Implementers:** +1. Implement `list_property_features` to advertise your capabilities +2. Implement property list CRUD operations +3. Support webhooks to notify buyers when evaluations change +4. See the [Protocol Specification](/docs/governance/property/specification) for implementation details + +See the [Protocol Specification](/docs/governance/property/specification) for detailed implementation guidance. diff --git a/docs/governance/property/specification.mdx b/docs/governance/property/specification.mdx new file mode 100644 index 0000000000..343d1c7e32 --- /dev/null +++ b/docs/governance/property/specification.mdx @@ -0,0 +1,611 @@ +--- +sidebar_position: 2 +title: Protocol Specification +--- + + +**AdCP 3.0 Proposal** - This specification is under development for AdCP 3.0. Feedback welcome via [GitHub Discussions](https://github.com/adcontextprotocol/adcp/discussions). + + +**Status**: Request for Comments +**Last Updated**: January 2026 + +## Abstract + +The Property Protocol defines a standard Model Context Protocol (MCP) and Agent-to-Agent (A2A) interface for property identity, authorization, data provision, and selection. This protocol enables publishers to declare properties and authorized agents, data providers to offer property intelligence, and buyers to select compliant property sets. + +## Overview + +The Property Protocol addresses four distinct concerns: + +| Concern | Question | Owner | Mechanism | +|---------|----------|-------|-----------| +| **Property Identity** | What properties exist? | Publishers | `adagents.json` properties array | +| **Sales Authorization** | Who can sell this property? | Publishers | `adagents.json` authorized_agents | +| **Property Data** | What do we know about this property? | Data providers | Governance agents via `list_property_features` | +| **Property Selection** | Which properties meet my requirements? | Buyers | Property lists with filters | + +The first two are **publisher-side declarations** via adagents.json. The last two are **buyer-side operations** that consume property data from governance agents. + +### Property Data and Selection + +Property data and selection use a **stateful** model: + +- **Feature discovery**: Agents advertise what they can evaluate via `list_property_features` +- **Property list management**: CRUD operations for managed property lists with filters +- **Brand manifests**: Let agents automatically apply rules based on brand characteristics +- **Webhook notifications**: Real-time updates when resolved lists change +- **Marketplace architecture**: Multiple specialized agents as subscription services + +All evaluation (scoring, filtering, discovery) happens implicitly when property lists are resolved via `get_property_list`. + +## Core Concepts + +### Request Roles and Relationships + +Every governance request involves two key roles: + +#### Orchestrator (Buyer Agent) +The platform or system making the API request to the governance agent. In AdCP documentation, this role is often called a "buyer agent" when operating in the media buying context. +- **Examples**: DSP, trading desk platform, campaign management tool +- **Responsibilities**: Makes API calls, handles authentication, manages the technical interaction +- **Account**: Has technical credentials and API access to the governance agent + +#### Principal +The entity on whose behalf the request is being made: +- **Examples**: Advertiser (Nike), agency (Omnicom), brand team +- **Responsibilities**: Owns the campaign objectives and policy requirements +- **Policies**: May have custom thresholds, blocklists, or compliance requirements + +### Property Identification + +Properties are identified using the standard AdCP property model: + +```json +{ + "property_type": "website", + "name": "Example News", + "identifiers": [ + { "type": "domain", "value": "example.com" } + ] +} +``` + +Property types include: `website`, `mobile_app`, `ctv_app`, `dooh`, `podcast`, `radio`, `streaming_audio`. + +### Property List References + +For large property sets, use property list references instead of embedding properties: + +```json +{ + "property_list_ref": { + "agent_url": "https://lists.example.com", + "list_id": "premium_news_sites", + "auth_token": "eyJhbGciOiJIUzI1NiIs..." + } +} +``` + +The receiving agent fetches and caches the list independently, enabling: +- **Scale**: Pass 50,000+ properties without payload bloat +- **Updates**: Lists evolve without changing requests +- **Authorization**: Token controls access to the list + +### Governance Agent Types + +#### Compliance Agents +Specialized vendors providing property compliance intelligence: +- **Examples**: Data integrity scoring, consent quality measurement +- **Business Model**: Subscription or per-query pricing +- **Methodology**: Published rubrics for transparency + +#### Brand Safety Agents +Content classification and risk assessment: +- **Examples**: Content categorization, brand safety scoring +- **Coverage**: May specialize by channel or geography + +#### Quality Agents +Performance and fraud measurement: +- **Examples**: Viewability prediction, IVT detection +- **Integration**: May correlate with campaign outcomes + +### Scoring and Data Privacy + +#### Scores Are Internal + +**Critical design principle**: Raw scores are NOT shared with buyers or downstream clients. This prevents data leakage. + +Governance agents maintain internal scoring models, but the protocol is designed around **list management**, not score exposure: + +- Buyers specify **thresholds** via `feature_requirements` (e.g., `"min_value": 85`) +- Agents return **pass/fail lists** of properties that meet the thresholds +- Raw scores never leave the governance agent + +This design prevents: +- Score enumeration attacks (running lists with different thresholds to reverse-engineer scores) +- Competitive intelligence leakage +- Data arbitrage where buyers resell scoring data + +#### What Buyers Receive + +When calling `get_property_list`, buyers receive a compact list of identifiers (not full property objects) for efficiency: + +```json +{ + "list_id": "pl_abc123", + "identifiers": [ + { "type": "domain", "value": "bbc.co.uk" }, + { "type": "domain", "value": "theguardian.com" }, + { "type": "domain", "value": "ft.com" } + ], + "total_count": 847 +} +``` + +Properties that pass the threshold are included. Properties that fail are excluded. No scores or property metadata are returned - just the identifiers needed for bid-time lookups. + +#### Methodology Discovery + +The `list_property_features` task returns information about what features an agent evaluates and their methodology, but NOT the underlying scores: + +```json +{ + "features": [ + { + "feature_id": "consent_quality", + "name": "Consent Quality Score", + "type": "quantitative", + "range": { "min": 0, "max": 100 }, + "methodology": "data_integrity_index", + "methodology_version": "v2.1", + "methodology_url": "https://compliance.example.com/methodology" + } + ] +} +``` + +This allows buyers to: +- Understand what an agent measures +- Compare methodologies across agents +- Set appropriate thresholds + +But they cannot retrieve the actual scores for individual properties. + +## Tasks + +### Discovery + +#### list_property_features + +Discover what features a governance agent can evaluate. + +**Use Cases**: +- Capability discovery: Understand what an agent can evaluate +- Marketplace browsing: Compare features across agents +- Integration planning: Know what filters are available before creating lists + +### Property List Management + +#### create_property_list + +Create a new property list with filters and optional brand manifest. + +**Required Parameters**: +- At least one country in `countries_all` (ISO country code) +- At least one channel in `channels_any` (display, video, audio, etc.) + +**Base Properties**: An array of property sources to evaluate. Each entry is a discriminated union with `selection_type` as the discriminator: +- **`publisher_tags`**: `{ "selection_type": "publisher_tags", "publisher_domain": "...", "tags": [...] }` - tags scoped to publisher +- **`publisher_ids`**: `{ "selection_type": "publisher_ids", "publisher_domain": "...", "property_ids": [...] }` - property IDs scoped to publisher +- **`identifiers`**: `{ "selection_type": "identifiers", "identifiers": [...] }` - no publisher context needed +- **Omitted**: Query the agent's entire property database + +See the [base-property-source schema](https://adcontextprotocol.org/schemas/v2/property/base-property-source.json) for the full specification. + +**Filter Logic** (explicit in field names): +- `countries_all`: Property must have feature data for **ALL** listed countries +- `channels_any`: Property must support **ANY** of the listed channels +- `feature_requirements`: Property must pass **ALL** requirements (AND) + +**Use Cases**: +- Define compliant property sets with filters (country, channel, feature thresholds) +- Provide brand manifest for automatic rule application +- Register webhook URL for change notifications + +#### update_property_list + +Modify an existing property list. + +**Use Cases**: +- Add or remove properties from base list +- Adjust filters based on campaign needs +- Update webhook URL + +#### get_property_list + +Retrieve a property list with resolved properties. + +**Use Cases**: +- Get the current list of compliant properties after filters applied +- Cache resolved list for bid-time use +- Retrieve updated list after webhook notification + +#### list_property_lists + +List all property lists accessible to the authenticated principal. + +#### delete_property_list + +Remove a property list. + +### Validation + +#### validate_property_delivery + +Validates delivery records against a property list to determine compliance. Closes the loop between "what I wanted" and "what I got." + +Performs two independent validations: +1. **Property compliance**: Is the identifier in the resolved property list? +2. **Supply path authorization**: Was the sales agent authorized to sell that property? (optional, requires `sales_agent_url`) + +**Use Cases**: +- Post-campaign validation: Verify impressions landed on compliant properties +- Supply path verification: Confirm sales agents were authorized by publishers +- Real-time monitoring: Check compliance rate during campaign execution +- Audit trails: Generate compliance reports for regulatory or brand safety reviews + +**Property Validation Statuses**: +- `compliant`: Identifier is in the resolved property list +- `non_compliant`: Identifier is NOT in the resolved property list +- `not_covered`: Identifier recognized but governance agent has no data for it (e.g., property too new) +- `unidentified`: Identifier type not resolvable by this agent (e.g., detection failed, unsupported type) + +**Authorization Validation Statuses** (when `sales_agent_url` provided): +- `authorized`: Sales agent is listed in publisher's adagents.json +- `unauthorized`: Sales agent is NOT in publisher's authorized_agents list +- `unknown`: Could not fetch or parse adagents.json + +**Unverifiable Records**: Both `not_covered` and `unidentified` records should be excluded when calculating compliance rates - you cannot penalize for detection gaps or coverage limitations. The distinction helps identify whether the gap is in the agent's data coverage vs the identifier resolution. + +**Response Format**: The response returns raw counts (compliant, non_compliant, not_covered, unidentified impressions). Consumers calculate rates as needed. Governance agents may optionally include an `aggregate` field with computed metrics (score, grade, label) - the format and meaning are agent-specific. + +## Typical Flows + +### Property List Flow + +Property lists enable buyers to define and manage compliant property sets: + +1. **Create property list**: Buyer defines list on governance agent with filters +2. **Resolve and iterate**: Buyer calls `get_property_list` to see resolved properties +3. **Share list reference**: Buyer provides `list_id` to orchestrator/seller +4. **Cache locally**: Orchestrator/seller fetches and caches resolved properties +5. **Use at bid time**: Orchestrator/seller uses local cache (no governance agent calls) +6. **Refresh periodically**: Re-fetch based on `cache_valid_until` (typically 1-24 hours) + +**Important**: Governance agents are NOT in the real-time bid path. All bid-time decisions use locally cached property sets. + +### Webhook and Caching Pattern + +Webhooks provide **notification** that a property list has changed. The webhook payload contains a summary of changes, but you must call `get_property_list` to retrieve the actual updated properties. + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Webhook Flow │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ 1. Governance agent re-evaluates properties (background) │ +│ 2. Webhook fires with change summary (added/removed counts) │ +│ 3. Recipient calls get_property_list to fetch updated list │ +│ 4. Recipient updates local cache │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +**Best Practices for Downstream Consumers**: + +Consumers of property lists (orchestrators, sellers, buyer agents) should implement **at least one** of these patterns: + +1. **Webhook-driven updates** (recommended): Register a webhook URL when creating the property list. Re-fetch via `get_property_list` when notified of changes. + +2. **Polling with cache hints**: Use `cache_valid_until` from `get_property_list` responses to schedule periodic re-fetches. Typical validity periods are 1-24 hours. + +3. **Hybrid approach**: Use webhooks for immediate updates, with polling as a fallback safety net. + +**Cache Expiry Guidance**: + +Every `get_property_list` response includes: +- `resolved_at`: When the list was evaluated +- `cache_valid_until`: When consumers should consider the cache stale + +```json +{ + "resolved_at": "2026-01-04T10:00:00Z", + "cache_valid_until": "2026-01-04T22:00:00Z" +} +``` + +Consumers MUST NOT use cached data beyond `cache_valid_until` without re-fetching. + +### Property Discovery Flow + +1. **Define filters**: Specify country, channel, quality thresholds when creating property list +2. **Resolve list**: Call `get_property_list` with `resolve=true` to get matching properties +3. **Review candidates**: Evaluate returned properties for fit +4. **Add to campaign**: Include property list reference in media buy + +## Response Structure + +All AdCP Governance responses follow a consistent structure: + +### Core Response Fields +- **message**: Human-readable summary of the operation result +- **context_id**: Session continuity identifier for follow-up requests +- **data**: Task-specific payload (varies by task) + +### Protocol Transport +- **MCP**: Returns complete response as flat JSON object +- **A2A**: Returns as structured artifacts with message in text part, data in data part +- **Data Consistency**: Both protocols contain identical AdCP data structures + +## Error Handling + +### Error Codes + +- `PROPERTY_NOT_FOUND`: Property identifier not recognized +- `PROPERTY_NOT_MONITORED`: Governance agent doesn't cover this property +- `POLICY_NOT_FOUND`: Referenced policy doesn't exist +- `LIST_ACCESS_DENIED`: Cannot access property list (auth failed) +- `LIST_NOT_FOUND`: Property list reference invalid +- `METHODOLOGY_NOT_SUPPORTED`: Requested methodology version unavailable +- `PARTIAL_RESULTS`: Some properties couldn't be evaluated + +### Partial Success + +For bulk operations, the response may include partial results: + +```json +{ + "message": "Evaluated 847 of 850 properties. 3 properties not in coverage.", + "context_id": "ctx-gov-123", + "scores": [...], + "errors": [ + { + "code": "PROPERTY_NOT_MONITORED", + "property": { "identifiers": [{ "type": "domain", "value": "unknown.com" }] }, + "message": "Property not in monitoring coverage" + } + ] +} +``` + +## Implementation Notes + +### Caching Architecture + +Governance decisions are highly cacheable: + +#### Orchestrator-Side Caching +- **Score cache**: Store scores with TTL from `valid_until` field +- **Decision cache**: Pre-compute pass/fail for campaigns +- **List cache**: Cache property lists from `property_list_ref` + +#### Agent-Side Caching +- **Profile cache**: Maintain pre-computed property profiles +- **Methodology cache**: Cache scoring algorithm results + +### Performance Requirements + +| Operation | Target Latency | +|-----------|----------------| +| Single property score | < 100ms | +| Bulk scoring (100 properties) | < 2s | +| Filter decision (cached) | < 5ms | +| Property discovery | < 5s | + +### Multi-Agent Strategies + +Orchestrators may consult multiple governance agents: + +1. **Primary + Validation**: Use primary agent, validate with secondary +2. **Specialization**: Route by property type to specialist agents +3. **Consensus**: Require multiple agents to agree +4. **Competitive**: Track agent accuracy, weight by performance + +## Agent Discovery + +Governance agents expose capabilities via `.well-known/agent-card.json`: + +```json +{ + "name": "Example Compliance Provider", + "url": "https://compliance.example.com", + "capabilities": { + "tasks": [ + "list_property_features", + "create_property_list", + "get_property_list", + "update_property_list", + "delete_property_list", + "list_property_lists", + "validate_property_delivery" + ], + "protocols": ["MCP", "A2A"], + "schema_version": "v1" + }, + "methodology": { + "documentation_url": "https://compliance.example.com/methodology", + "scoring_frameworks": ["data_integrity_index", "brand_safety_score"], + "coverage": { + "property_types": ["website", "mobile_app", "ctv_app"], + "jurisdictions": ["GDPR", "CCPA", "COPPA"] + } + } +} +``` + +Use `list_property_features` for detailed capability discovery: + +```json +{ + "tool": "list_property_features", + "arguments": {} +} +``` + +Returns the specific features the agent can evaluate (consent_quality, carbon_score, brand_risk, etc.). + +## Marketplace Architecture + +The Property Protocol enables a marketplace of specialized data agents: + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ SELLER AGENT (DSP/SSP) │ +│ "Give me the compliant property list for this campaign" │ +└───────────────────────────────┬─────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ BUYER AGENT (implements Property Protocol) │ +│ - Exposes: list_property_features, get_property_list, webhooks │ +│ - Source of truth for final compliant list │ +│ - Intersects results from specialized agents │ +└───────────────────────────┬─────────────────────────────────────────────┘ + │ + ┌───────────────────┼───────────────────┐ + ▼ ▼ ▼ +┌───────────────┐ ┌───────────────┐ ┌───────────────┐ +│ Consent Agent │ │ Scope3 Agent │ │ Brand Safety │ +│ (Compliant) │ │ │ │ Agent │ +├───────────────┤ ├───────────────┤ ├───────────────┤ +│ Features: │ │ Features: │ │ Features: │ +│ consent_qual │ │ carbon_score │ │ content_cat │ +│ tcf_version │ │ climate_risk │ │ brand_risk │ +│ coppa_cert │ │ green_host │ │ sentiment │ +├───────────────┤ ├───────────────┤ ├───────────────┤ +│ Subscription │ │ Subscription │ │ Subscription │ +└───────────────┘ └───────────────┘ └───────────────┘ +``` + +### Key Principles + +1. **Buyer agent is source of truth**: The buyer agent aggregates data from multiple specialized governance agents +2. **Seller sees one interface**: Sellers interact only with the buyer agent using standard Property Protocol +3. **Subscription model**: Each specialized agent is a paid service with its own features and coverage +4. **Webhook-driven updates**: Specialized agents notify the buyer agent when property evaluations change + +### Multi-Agent Orchestration + +A buyer agent can distribute a master property list to multiple specialized agents: + +```python +# Buyer agent creates variants on each specialized agent +consent_list = consent_agent.create_property_list( + name="Q1 Campaign - Consent", + base_properties=master_list, + brand_manifest=brand_manifest +) +# Configure webhook for updates +consent_agent.update_property_list( + list_id=consent_list.list_id, + webhook_url="https://buyer.example.com/webhooks/consent" +) + +scope3_list = scope3_agent.create_property_list( + name="Q1 Campaign - Sustainability", + base_properties=master_list, + brand_manifest=brand_manifest +) +scope3_agent.update_property_list( + list_id=scope3_list.list_id, + webhook_url="https://buyer.example.com/webhooks/scope3" +) + +# Buyer agent intersects filtered results +def on_list_changed(event): + consent_props = consent_agent.get_property_list(consent_list.list_id, resolve=True) + scope3_props = scope3_agent.get_property_list(scope3_list.list_id, resolve=True) + + # Intersection = properties that pass ALL governance agents + compliant_props = intersect(consent_props, scope3_props) + + # Update buyer agent's exposed list + update_compliant_list(compliant_props) +``` + +### Brand Manifest + +Instead of specifying complex filters, buyers provide a brand manifest: + +```json +{ + "brand_manifest": { + "brand_name": "ToyBrand", + "industry": "toys", + "target_audience": "children_under_13", + "content_adjacency": ["kids_family", "education"], + "excluded_content": ["violence", "adult"] + } +} +``` + +Each governance agent interprets the manifest according to their domain expertise: +- **Consent agent**: Applies COPPA requirements for children_under_13 +- **Brand safety agent**: Filters to kids_family content, excludes violence/adult +- **Sustainability agent**: Applies any green media requirements + +The buyer doesn't need to know the specific rules - they declare who they are, and agents figure out what applies. + +## Integration with Media Buy Protocol + +### Property Lists in Media Buys + +The Media Buy Protocol accepts property list references: + +```json +{ + "task": "create_media_buy", + "arguments": { + "packages": [{ + "property_list_ref": { + "agent_url": "https://governance.example.com", + "list_id": "approved_q1_campaign", + "auth_token": "..." + } + }] + } +} +``` + +### Policy Compliance + +Media buys can reference governance policies via property list references: + +```json +{ + "compliance_requirements": { + "property_list_ref": { + "agent_url": "https://compliance.example.com", + "list_id": "pl_q1_compliant", + "auth_token": "eyJhbGciOiJIUzI1NiIs..." + } + } +} +``` + +## Best Practices + +1. **Cache aggressively**: Property scores change slowly; cache for hours/days +2. **Bulk where possible**: Use batch operations for planning, not per-property calls +3. **Pre-compute decisions**: Build pass/fail lookups before bid-time +4. **Monitor coverage**: Track which properties agents don't cover +5. **Log methodology versions**: For audit trails, record which scoring version was used +6. **Handle partial results**: Not all properties will be scorable; plan for gaps + +## Next Steps + +- See the [adagents.json Tech Spec](/docs/governance/property/adagents) for property declaration and authorization +- See the [list_property_features task reference](/docs/governance/property/tasks/list_property_features) for capability discovery +- See the [Property List Management](/docs/governance/property/tasks/property_lists) for CRUD operations and webhooks +- See the [validate_property_delivery task reference](/docs/governance/property/tasks/validate_property_delivery) for post-campaign compliance validation diff --git a/docs/governance/property/tasks/index.mdx b/docs/governance/property/tasks/index.mdx new file mode 100644 index 0000000000..4679e3704b --- /dev/null +++ b/docs/governance/property/tasks/index.mdx @@ -0,0 +1,153 @@ +--- +sidebar_position: 1 +title: Task Reference +--- + +# Property Governance Tasks + + +**AdCP 3.0 Proposal** - These tasks are under development for AdCP 3.0. + + +Property governance uses a **stateful** model where all evaluation happens through property list management. Create lists with filters and brand manifests, then resolve them to get compliant properties. + +## Discovery + +| Task | Purpose | Response Time | +|------|---------|---------------| +| [list_property_features](/docs/governance/property/tasks/list_property_features) | Discover agent capabilities | ~200ms | + +## Property List Management + +| Task | Purpose | Response Time | +|------|---------|---------------| +| [create_property_list](/docs/governance/property/tasks/property_lists#create_property_list) | Create a new property list | ~500ms | +| [update_property_list](/docs/governance/property/tasks/property_lists#update_property_list) | Modify an existing list | ~500ms | +| [get_property_list](/docs/governance/property/tasks/property_lists#get_property_list) | Retrieve list with resolved properties | ~2-5s | +| [list_property_lists](/docs/governance/property/tasks/property_lists#list_property_lists) | List all property lists | ~500ms | +| [delete_property_list](/docs/governance/property/tasks/property_lists#delete_property_list) | Delete a property list | ~200ms | + +See [Property List Management](/docs/governance/property/tasks/property_lists) for complete CRUD documentation. + +## Validation + +| Task | Purpose | Response Time | +|------|---------|---------------| +| [validate_property_delivery](/docs/governance/property/tasks/validate_property_delivery) | Validate delivery records against a list | ~1-5s | + +See [validate_property_delivery](/docs/governance/property/tasks/validate_property_delivery) for post-campaign compliance validation. + +## Task Selection Guide + +### Creating a Property List + +Use `create_property_list` with filters and brand manifest: + +```json +{ + "tool": "create_property_list", + "arguments": { + "name": "Q1 Campaign - UK Premium", + "base_properties": [ + { + "selection_type": "publisher_tags", + "publisher_domain": "raptive.com", + "tags": ["premium_news"] + } + ], + "filters": { + "countries_all": ["UK"], + "channels_any": ["display", "video"], + "feature_requirements": [ + { + "feature_id": "consent_quality", + "min_value": 85, + "max_value": 100 + }, + { + "feature_id": "coppa_certified", + "allowed_values": [true] + } + ] + }, + "brand_manifest": { + "name": "ToyBrand", + "industry": "toys", + "target_audience": "children_under_13" + } + } +} +``` + +**Required filters**: At least one country in `countries_all` and one channel in `channels_any` must be provided. + +**Base properties**: An array of property sources to evaluate. Each entry is a discriminated union with `selection_type`: +- **`publisher_tags`**: `{ "selection_type": "publisher_tags", "publisher_domain": "...", "tags": [...] }` +- **`publisher_ids`**: `{ "selection_type": "publisher_ids", "publisher_domain": "...", "property_ids": [...] }` +- **`identifiers`**: `{ "selection_type": "identifiers", "identifiers": [...] }` +- **Omitted**: Query the agent's entire property database + +**Filter logic** (explicit in field names): +- `countries_all`: Property must have feature data for ALL listed countries +- `channels_any`: Property must support ANY of the listed channels +- `feature_requirements`: Property must pass ALL requirements (AND) + +Filters have two built-in fields (`countries_all`, `channels_any`) plus `feature_requirements` which reference features the agent provides (discovered via `list_property_features`). For quantitative features, use `min_value`/`max_value`. For binary or categorical features, use `allowed_values`. + +### Getting Resolved Properties + +Use `get_property_list` to retrieve the list with resolved identifiers: + +```json +{ + "tool": "get_property_list", + "arguments": { + "list_id": "pl_abc123", + "resolve": true + } +} +``` + +Response includes resolved identifiers. Note that **raw scores are not returned** - only identifiers that pass the filter thresholds are included: + +```json +{ + "list_id": "pl_abc123", + "identifiers": [ + { "type": "domain", "value": "bbc.co.uk" }, + { "type": "domain", "value": "news.sky.com" } + ], + "cache_valid_until": "2026-01-04T17:15:00Z" +} +``` + +The `auth_token` for sharing with sellers is returned at creation time (from `create_property_list`). Store it securely - it's only returned once. + +### Multi-Agent Integration + +Create the same property list on multiple governance agents, then configure webhooks to aggregate results: + +```python +# Create lists on specialized agents +consent_list = consent_agent.create_property_list( + name="Q1 - Consent", + base_properties=master_list, + brand_manifest=brand_manifest +) +consent_agent.update_property_list( + list_id=consent_list.list_id, + webhook_url="https://buyer.example.com/webhooks/consent" +) + +scope3_list = scope3_agent.create_property_list( + name="Q1 - Sustainability", + base_properties=master_list, + brand_manifest=brand_manifest +) +scope3_agent.update_property_list( + list_id=scope3_list.list_id, + webhook_url="https://buyer.example.com/webhooks/scope3" +) + +# Buyer agent intersects results when webhooks fire +``` diff --git a/docs/governance/property/tasks/list_property_features.mdx b/docs/governance/property/tasks/list_property_features.mdx new file mode 100644 index 0000000000..6c7dcd16a7 --- /dev/null +++ b/docs/governance/property/tasks/list_property_features.mdx @@ -0,0 +1,235 @@ +--- +sidebar_position: 1 +title: list_property_features +--- + + +**AdCP 3.0 Proposal** - This task is under development for AdCP 3.0. + + +**Task**: Discover what features a property governance agent can evaluate. + +**Response Time**: ~200ms + +**Request Schema**: [`https://adcontextprotocol.org/schemas/v1/governance/list-property-features-request.json`](https://adcontextprotocol.org/schemas/v1/governance/list-property-features-request.json) +**Response Schema**: [`https://adcontextprotocol.org/schemas/v1/governance/list-property-features-response.json`](https://adcontextprotocol.org/schemas/v1/governance/list-property-features-response.json) + +The `list_property_features` task returns the features a governance agent can evaluate. This is the discovery mechanism for understanding an agent's capabilities before using other governance tasks. + +## Request Parameters + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `property_types` | string[] | No | Filter to features available for these property types | +| `countries` | string[] | No | Filter to features available in these countries | + +## Response Structure + +All AdCP responses include: +- **message**: Human-readable summary of the operation result +- **context_id**: Session continuity identifier for follow-up requests +- **data**: Task-specific payload (see Response Data below) + +## Response Data + +```json +{ + "features": [ + { + "feature_id": "consent_quality", + "name": "Consent Quality Score", + "description": "Measures the quality of consent implementation including UX, granularity, and compliance", + "type": "quantitative", + "range": { "min": 0, "max": 100 }, + "coverage": { + "property_types": ["website", "mobile_app"], + "countries": [] + } + }, + { + "feature_id": "coppa_certified", + "name": "COPPA Certified", + "description": "Whether the property has COPPA certification for child-directed content", + "type": "binary", + "coverage": { + "property_types": ["website", "mobile_app", "ctv_app"], + "countries": ["US"] + } + }, + { + "feature_id": "content_category", + "name": "Content Category", + "description": "IAB content category classification", + "type": "categorical", + "allowed_values": ["news", "sports", "entertainment", "kids_family", "technology", "business", "adult", "violence"] + } + ] +} +``` + +### Feature Types + +| Type | Description | Schema Fields | +|------|-------------|---------------| +| `binary` | True/false values | None additional | +| `quantitative` | Numeric values within a range | `range: { min, max }` | +| `categorical` | Enumerated string values | `allowed_values: string[]` | + +### Coverage + +The `coverage` object indicates where a feature applies: +- **property_types**: Empty array means all property types +- **countries**: Empty array means all countries + +## Protocol-Specific Examples + +### MCP Request + +```json +{ + "tool": "list_property_features", + "arguments": {} +} +``` + +### MCP Response + +```json +{ + "message": "This agent evaluates 12 features across consent, brand safety, and sustainability.", + "context_id": "ctx-gov-features-123", + "features": [ + { + "feature_id": "consent_quality", + "name": "Consent Quality Score", + "description": "Measures the quality of consent implementation", + "type": "quantitative", + "range": { "min": 0, "max": 100 } + }, + { + "feature_id": "tcf_version", + "name": "TCF Version", + "description": "IAB Transparency & Consent Framework version supported", + "type": "categorical", + "allowed_values": ["none", "tcf_1.1", "tcf_2.0", "tcf_2.2"] + }, + { + "feature_id": "coppa_certified", + "name": "COPPA Certified", + "description": "Whether property has COPPA certification", + "type": "binary", + "coverage": { + "property_types": ["website", "mobile_app", "ctv_app"], + "countries": ["US"] + } + } + ] +} +``` + +### MCP Request - Filtered by Property Type + +```json +{ + "tool": "list_property_features", + "arguments": { + "property_types": ["mobile_app"] + } +} +``` + +### A2A Request + +```javascript +await a2a.send({ + message: { + parts: [{ + kind: "data", + data: { + skill: "list_property_features", + parameters: {} + } + }] + } +}); +``` + +## Example Feature Sets by Agent Type + +### Consent/Compliance Agent + +```json +{ + "features": [ + { "feature_id": "consent_quality", "type": "quantitative", "range": { "min": 0, "max": 100 } }, + { "feature_id": "tcf_version", "type": "categorical", "allowed_values": ["none", "tcf_2.0", "tcf_2.2"] }, + { "feature_id": "coppa_certified", "type": "binary" }, + { "feature_id": "gpp_supported", "type": "binary" }, + { "feature_id": "vendor_count", "type": "quantitative", "range": { "min": 0, "max": 1000 } } + ] +} +``` + +### Sustainability Agent (e.g., Scope3) + +```json +{ + "features": [ + { "feature_id": "carbon_score", "type": "quantitative", "range": { "min": 0, "max": 100 } }, + { "feature_id": "green_certified", "type": "binary" }, + { "feature_id": "renewable_hosting", "type": "binary" }, + { "feature_id": "emissions_per_impression", "type": "quantitative", "range": { "min": 0, "max": 100 } } + ] +} +``` + +### Brand Safety Agent + +```json +{ + "features": [ + { "feature_id": "content_category", "type": "categorical", "allowed_values": ["news", "sports", ...] }, + { "feature_id": "brand_risk_score", "type": "quantitative", "range": { "min": 0, "max": 100 } }, + { "feature_id": "sentiment", "type": "categorical", "allowed_values": ["positive", "neutral", "negative"] }, + { "feature_id": "made_for_advertising", "type": "binary" } + ] +} +``` + +## Integration Pattern + +Use `list_property_features` to understand agent capabilities before creating property lists: + +```python +# Step 1: Discover agent capabilities +features_response = governance_agent.list_property_features() + +# Step 2: Build feature_requirements using available features +feature_requirements = [] +for feature in features_response.features: + if feature.feature_id == "consent_quality" and feature.type == "quantitative": + feature_requirements.append({ + "feature_id": "consent_quality", + "min_value": 80, + "max_value": 100 + }) + if feature.feature_id == "coppa_certified" and feature.type == "binary": + feature_requirements.append({ + "feature_id": "coppa_certified", + "allowed_values": [True] + }) + +# Step 3: Create property list with feature requirements +governance_agent.create_property_list( + name="Q1 Campaign", + filters={"feature_requirements": feature_requirements}, + brand_manifest=my_brand_manifest +) +``` + +## Usage Notes + +1. **Call first**: Use this task to discover capabilities before other governance tasks +2. **Cache results**: Feature definitions change infrequently; cache for hours/days +3. **Check coverage**: Not all features apply to all property types or countries +4. **Marketplace discovery**: Use this to understand what different governance agents offer diff --git a/docs/governance/property/tasks/property_lists.mdx b/docs/governance/property/tasks/property_lists.mdx new file mode 100644 index 0000000000..a46e54545f --- /dev/null +++ b/docs/governance/property/tasks/property_lists.mdx @@ -0,0 +1,701 @@ +--- +sidebar_position: 5 +title: Property List Management +--- + + +**AdCP 3.0 Proposal** - These tasks are under development for AdCP 3.0. + + +**Tasks**: Create, update, get, list, and delete property lists. + +Property lists are managed resources that combine static property sets with dynamic filters. When resolved, filters are applied to produce the final property set. + +## Architecture: Setup Time, Not Real-Time + +Property lists are designed for **setup-time** operations, not real-time bid decisions: + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ SETUP TIME (Campaign Planning) │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ 1. Buyer creates/updates property list on governance agent │ +│ 2. Buyer resolves list to get current properties │ +│ 3. Buyer provides list_id to orchestrator/seller │ +│ 4. Orchestrator/seller fetches and caches resolved list │ +│ 5. Campaign targets only cached compliant properties │ +│ │ +└─────────────────────────────────────────────────────────────────┘ + +┌─────────────────────────────────────────────────────────────────┐ +│ BID TIME (Milliseconds) │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ • Orchestrator/seller uses LOCAL cache only │ +│ • NO calls to governance agent │ +│ • Pass/fail from cached property set │ +│ │ +└─────────────────────────────────────────────────────────────────┘ + +┌─────────────────────────────────────────────────────────────────┐ +│ REFRESH (Periodic) │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ • Orchestrator/seller re-fetches list on schedule │ +│ • Frequency based on cache_valid_until │ +│ • Typically every 1-24 hours │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +This enables: + +- **Static lists**: Curated sets of approved properties +- **Dynamic lists**: Properties matching criteria (country, channel, score thresholds) +- **Hybrid lists**: Base set modified by filters + +## Tasks Overview + +| Task | Purpose | Response Time | +|------|---------|---------------| +| `create_property_list` | Create a new property list | ~500ms | +| `update_property_list` | Modify an existing list | ~500ms | +| `get_property_list` | Retrieve list with resolved properties | ~2-5s (depending on size) | +| `list_property_lists` | List all property lists | ~500ms | +| `delete_property_list` | Delete a property list | ~200ms | + +## Property List Structure + +A property list contains: + +```json +{ + "list_id": "uk_premium_news_q1", + "name": "UK Premium News Sites Q1 2026", + "description": "High-quality UK news sites for Q1 campaign", + "principal": "did:principal:brand-x", + "base_properties": [ + { + "selection_type": "publisher_tags", + "publisher_domain": "raptive.com", + "tags": ["premium_news", "uk_tier1"] + } + ], + "filters": { + "countries_all": ["UK"], + "channels_any": ["display", "video"], + "feature_requirements": [ + { "feature_id": "consent_quality", "min_value": 90, "max_value": 100 } + ] + }, + "brand_manifest": { + "industry": "retail", + "target_audience": "general" + }, + "created_at": "2026-01-03T10:00:00Z", + "updated_at": "2026-01-03T10:00:00Z", + "property_count": 847 +} +``` + +## Brand Manifest + +Instead of manually specifying all filters, provide a brand manifest and let the governance agent apply appropriate rules based on who you are: + +```json +{ + "brand_manifest": { + "name": "ToyBrand", + "industry": "toys", + "target_audience": "children under 13", + "tone": "playful and safe" + } +} +``` + +The agent interprets the manifest based on its domain expertise: +- A consent agent applies COPPA requirements based on `target_audience` +- A brand safety agent infers content categories from `industry` +- A sustainability agent applies requirements from the brand's profile + +The brand manifest uses the standard [core/brand-manifest](https://adcontextprotocol.org/schemas/v2/core/brand-manifest.json) schema which includes fields for `industry`, `target_audience`, `tone`, and other brand identity information. + +## Webhooks + +Configure webhooks via `update_property_list` to receive notifications when the resolved list changes. + +**Important**: Webhooks provide **notification only**. They tell you that the list has changed, but do not stream the updated properties. After receiving a webhook, you must call `get_property_list` to retrieve the updated property set. + +### Webhook Flow + +``` +1. Governance agent re-evaluates properties (periodically or on trigger) +2. Agent detects changes to the resolved property list +3. Webhook fires with change summary (counts, not full list) +4. Recipient calls get_property_list(list_id, resolve=true) +5. Recipient updates local cache with new properties +``` + +### Webhook Payload + +```json +{ + "event": "property_list_changed", + "list_id": "uk_premium_news_q1", + "list_name": "UK Premium News Sites Q1 2026", + "change_summary": { + "properties_added": 12, + "properties_removed": 3, + "total_properties": 856 + }, + "resolved_at": "2026-01-03T18:00:00Z", + "cache_valid_until": "2026-01-04T18:00:00Z" +} +``` + +The webhook payload includes counts but NOT the actual properties. This keeps payloads small and avoids redundant data transfer when recipients may not need the full list immediately. + +### Webhook Use Cases + +1. **Buyer agent aggregation**: Receive updates from multiple specialized agents, intersect results +2. **Seller cache invalidation**: Know when to re-fetch the compliant property list +3. **Alerting**: Notify when significant changes occur to compliance status + +## Filters + +Filters are applied when the list is resolved (via `get_property_list`): + +| Filter | Type | Description | +|--------|------|-------------| +| `countries_all` | string[] | ISO country codes - property must have feature data for ALL (required) | +| `channels_any` | string[] | Advertising channels - property must support ANY (required) | +| `property_types` | string[] | Property types (website, mobile_app, ctv_app, etc.) | +| `feature_requirements` | FeatureRequirement[] | Requirements based on agent-provided features | +| `exclude_identifiers` | Identifier[] | Identifiers to always exclude | + +### Feature Requirements + +Feature requirements reference features discovered via `list_property_features`. Each agent exposes different features (consent_quality, carbon_score, coppa_certified, etc.). + +For **quantitative** features (scores, ranges): +```json +{ "feature_id": "consent_quality", "min_value": 85, "max_value": 100 } +``` + +For **binary** features (true/false): +```json +{ "feature_id": "coppa_certified", "allowed_values": [true] } +``` + +For **categorical** features (enum values): +```json +{ "feature_id": "content_category", "allowed_values": ["news", "sports", "technology"] } +``` + +### Handling Missing Coverage + +When a property doesn't have data for a required feature, you can control the behavior with `if_not_covered`: + +```json +{ + "feature_id": "viewability_score", + "min_value": 70, + "if_not_covered": "include" +} +``` + +| Value | Behavior | Use Case | +|-------|----------|----------| +| `exclude` (default) | Property is removed from the list | Strict enforcement - only include properties with verified data | +| `include` | Property passes this requirement | Lenient enforcement - don't penalize for coverage gaps | + +When `if_not_covered: "include"` is used, the response includes a `coverage_gaps` field showing which properties were included despite missing data: + +```json +{ + "identifiers": [...], + "coverage_gaps": { + "viewability_score": [ + { "type": "domain", "value": "app.example.com" }, + { "type": "domain", "value": "ctv.example.com" } + ] + } +} +``` + +This transparency helps agencies distinguish between properties that passed a requirement vs. those that couldn't be evaluated. + +### Required Filters + +Every property list must include at least: +- One country in `countries_all` (ISO country code) +- One channel in `channels_any` (display, video, audio, etc.) + +These are required because governance agents need to know which jurisdiction and context to evaluate properties against. + +### Filter Logic + +The filter field names make the logic explicit: + +- **`countries_all`**: Property must have feature data for **ALL** listed countries. +- **`channels_any`**: Property must support **ANY** of the listed channels. +- **`feature_requirements`**: Property must pass **ALL** requirements (AND). + +### Base Properties + +`base_properties` is an array of property sources to evaluate. Each entry is a **discriminated union** with `selection_type` as the discriminator: + +```json +{ + "base_properties": [ + { + "selection_type": "publisher_tags", + "publisher_domain": "raptive.com", + "tags": ["premium_news", "tier1"] + }, + { + "selection_type": "publisher_tags", + "publisher_domain": "mediavine.com", + "tags": ["lifestyle"] + }, + { + "selection_type": "identifiers", + "identifiers": [ + { "type": "domain", "value": "bbc.co.uk" }, + { "type": "domain", "value": "ft.com" } + ] + } + ] +} +``` + +Each entry must include `selection_type`: + +| selection_type | Required Fields | Description | +|-------------|-----------------|-------------| +| `publisher_tags` | `publisher_domain`, `tags` | All properties matching these tags within the publisher | +| `publisher_ids` | `publisher_domain`, `property_ids` | Specific property IDs within the publisher | +| `identifiers` | `identifiers` | Direct domain/app identifiers (no publisher context) | + +If `base_properties` is omitted, the agent queries its entire property database for properties matching the filters. + +See the [base-property-source schema](https://adcontextprotocol.org/schemas/v2/property/base-property-source.json) for the full specification. + +--- + +## create_property_list + +Create a new property list. + +### Request + +```json +{ + "tool": "create_property_list", + "arguments": { + "name": "UK Premium News Q1", + "description": "High-quality UK news sites for Q1 campaign", + "base_properties": [ + { + "selection_type": "publisher_tags", + "publisher_domain": "raptive.com", + "tags": ["premium_news"] + } + ], + "filters": { + "countries_all": ["UK"], + "channels_any": ["display", "video"], + "feature_requirements": [ + { "feature_id": "consent_quality", "min_value": 85, "max_value": 100 } + ] + } + } +} +``` + +### Response + +```json +{ + "message": "Created property list 'UK Premium News Q1'.", + "context_id": "ctx-gov-list-123", + "list": { + "list_id": "pl_abc123", + "name": "UK Premium News Q1", + "description": "High-quality UK news sites for Q1 campaign", + "principal": "did:principal:brand-x", + "base_properties": [ + { + "selection_type": "publisher_tags", + "publisher_domain": "raptive.com", + "tags": ["premium_news"] + } + ], + "filters": { + "countries_all": ["UK"], + "channels_any": ["display", "video"], + "feature_requirements": [ + { "feature_id": "consent_quality", "min_value": 85, "max_value": 100 } + ] + }, + "created_at": "2026-01-03T16:30:00Z", + "updated_at": "2026-01-03T16:30:00Z", + "property_count": 847 + }, + "auth_token": "eyJhbGciOiJIUzI1NiIs..." +} +``` + +### Dynamic List (Filters Only) + +Create a list that dynamically queries the governance agent's database (no base_properties - uses agent's full coverage): + +```json +{ + "tool": "create_property_list", + "arguments": { + "name": "GDPR-Compliant DE Video", + "description": "All DE properties supporting video with strong consent", + "filters": { + "countries_all": ["DE"], + "channels_any": ["video"], + "feature_requirements": [ + { "feature_id": "consent_quality", "min_value": 90, "max_value": 100 } + ] + } + } +} +``` + +--- + +## update_property_list + +Modify an existing property list. + +### Request - Update Filters + +```json +{ + "tool": "update_property_list", + "arguments": { + "list_id": "pl_abc123", + "filters": { + "countries_all": ["UK"], + "channels_any": ["display", "video"], + "feature_requirements": [ + { "feature_id": "consent_quality", "min_value": 80, "max_value": 100 } + ] + } + } +} +``` + +### Request - Replace Base Properties + +```json +{ + "tool": "update_property_list", + "arguments": { + "list_id": "pl_abc123", + "base_properties": [ + { + "selection_type": "publisher_tags", + "publisher_domain": "raptive.com", + "tags": ["premium_news", "uk_tier1"] + } + ] + } +} +``` + +### Request - Add Exclusions + +```json +{ + "tool": "update_property_list", + "arguments": { + "list_id": "pl_abc123", + "filters": { + "exclude_identifiers": [ + { "type": "domain", "value": "excluded-site.com" } + ] + } + } +} +``` + +### Response + +```json +{ + "message": "Updated property list 'UK Premium News Q1'.", + "context_id": "ctx-gov-list-456", + "list": { + "list_id": "pl_abc123", + "name": "UK Premium News Q1", + "updated_at": "2026-01-03T17:00:00Z", + "property_count": 845 + } +} +``` + +--- + +## get_property_list + +Retrieve a property list with optional resolution of filters. + +### Request - Get Resolved Properties + +```json +{ + "tool": "get_property_list", + "arguments": { + "list_id": "pl_abc123", + "resolve": true, + "max_results": 100 + } +} +``` + +### Response + +The response returns a compact list of **identifiers only** (not full property objects) for efficiency. Only identifiers that pass the feature requirements are included - no scores or metadata. + +```json +{ + "message": "Retrieved property list 'UK Premium News Q1' with 847 resolved identifiers.", + "context_id": "ctx-gov-list-789", + "list_id": "pl_abc123", + "identifiers": [ + { "type": "domain", "value": "bbc.co.uk" }, + { "type": "domain", "value": "news.sky.com" }, + { "type": "domain", "value": "ft.com" }, + { "type": "domain", "value": "theguardian.com" } + ], + "total_count": 847, + "returned_count": 100, + "pagination": { + "has_more": true, + "cursor": "eyJvZmZzZXQiOjEwMH0=" + }, + "resolved_at": "2026-01-03T17:15:00Z", + "cache_valid_until": "2026-01-04T17:15:00Z" +} +``` + + +The `auth_token` is only returned when the list is created via `create_property_list`. Store it securely - you'll need it to share access with sellers. + + +### Request - Get Metadata Only + +```json +{ + "tool": "get_property_list", + "arguments": { + "list_id": "pl_abc123", + "resolve": false + } +} +``` + +### Response (Metadata Only) + +```json +{ + "message": "Retrieved property list 'UK Premium News Q1' metadata.", + "context_id": "ctx-gov-list-790", + "list": { + "list_id": "pl_abc123", + "name": "UK Premium News Q1", + "description": "High-quality UK news sites for Q1 campaign", + "base_properties": [ + { + "selection_type": "publisher_tags", + "publisher_domain": "raptive.com", + "tags": ["premium_news"] + } + ], + "filters": { + "countries_all": ["UK"], + "channels_any": ["display", "video"], + "feature_requirements": [ + { "feature_id": "consent_quality", "min_value": 85, "max_value": 100 } + ] + }, + "created_at": "2026-01-03T16:30:00Z", + "updated_at": "2026-01-03T17:00:00Z", + "property_count": 847 + } +} +``` + +--- + +## list_property_lists + +List all property lists accessible to the authenticated principal. + +### Request + +```json +{ + "tool": "list_property_lists", + "arguments": { + "name_contains": "UK", + "max_results": 50 + } +} +``` + +### Response + +```json +{ + "message": "Found 3 property lists matching 'UK'.", + "context_id": "ctx-gov-list-list-123", + "lists": [ + { + "list_id": "pl_abc123", + "name": "UK Premium News Q1", + "description": "High-quality UK news sites for Q1 campaign", + "created_at": "2026-01-03T16:30:00Z", + "updated_at": "2026-01-03T17:00:00Z", + "property_count": 847 + }, + { + "list_id": "pl_def456", + "name": "UK Sports Sites", + "description": "UK sports content for sponsorship", + "created_at": "2026-01-02T10:00:00Z", + "updated_at": "2026-01-02T10:00:00Z", + "property_count": 156 + } + ], + "total_count": 3, + "returned_count": 3, + "pagination": { + "has_more": false + } +} +``` + +--- + +## delete_property_list + +Delete a property list. + +### Request + +```json +{ + "tool": "delete_property_list", + "arguments": { + "list_id": "pl_abc123" + } +} +``` + +### Response + +```json +{ + "message": "Deleted property list 'UK Premium News Q1'.", + "context_id": "ctx-gov-list-del-123", + "deleted": true, + "list_id": "pl_abc123" +} +``` + +--- + +## Integration with Other Tasks + +### Using Lists in score_properties + +Reference a property list instead of passing properties inline: + +```json +{ + "tool": "score_properties", + "arguments": { + "property_list_ref": { + "agent_url": "https://governance.example.com", + "list_id": "pl_abc123" + }, + "scoring_context": { + "jurisdiction": "GDPR" + } + } +} +``` + +### Using Lists in Media Buys + +Pass property lists to media buy creation: + +```json +{ + "tool": "create_media_buy", + "arguments": { + "packages": [{ + "property_list_ref": { + "agent_url": "https://governance.example.com", + "list_id": "pl_abc123" + } + }] + } +} +``` + +--- + +## Error Codes + +| Code | Description | +|------|-------------| +| `LIST_NOT_FOUND` | Property list ID doesn't exist | +| `LIST_ACCESS_DENIED` | Principal doesn't have access to this list | +| `INVALID_FILTER` | Filter configuration is invalid | +| `LIST_NAME_EXISTS` | A list with this name already exists | + +## Caching and Refresh + +The `get_property_list` response includes caching guidance: + +| Field | Description | +|-------|-------------| +| `resolved_at` | When filters were applied and properties resolved | +| `cache_valid_until` | When consumers should re-fetch the list | + +**Typical flow for orchestrators/sellers:** + +```python +# Initial setup +response = governance_agent.get_property_list(list_id, resolve=True) +local_cache = build_property_lookup(response.properties) +cache_expiry = response.cache_valid_until + +# Periodic refresh (background job) +if now() >= cache_expiry: + response = governance_agent.get_property_list(list_id, resolve=True) + local_cache = build_property_lookup(response.properties) + cache_expiry = response.cache_valid_until + +# Bid time (no external calls) +def should_bid(property_domain): + return property_domain in local_cache +``` + +## Usage Notes + +1. **Setup time only**: Governance agents are not in the real-time bid path; resolve lists during campaign setup +2. **Local caching**: Orchestrators/sellers must cache resolved properties locally for bid-time decisions +3. **Refresh on schedule**: Re-fetch lists based on `cache_valid_until` (typically every 1-24 hours) +4. **Dynamic vs Static**: Use filters-only lists when you want the agent to maintain the property set; use base_properties when you need explicit control +5. **Pagination**: Large lists may require multiple requests with cursor-based pagination +6. **No score leakage**: Raw scores are kept internal to governance agents; responses contain pass/fail lists, not scores diff --git a/docs/governance/property/tasks/validate_property_delivery.mdx b/docs/governance/property/tasks/validate_property_delivery.mdx new file mode 100644 index 0000000000..7f9acc8c42 --- /dev/null +++ b/docs/governance/property/tasks/validate_property_delivery.mdx @@ -0,0 +1,402 @@ +--- +sidebar_position: 4 +title: validate_property_delivery +--- + +# validate_property_delivery + + +**AdCP 3.0 Proposal** - This task is under development for AdCP 3.0. + + +Validates delivery records against a property list to determine compliance. Answers two questions: +1. **Property compliance**: Did my impressions land on properties in my list? +2. **Supply path authorization**: Was the sales agent authorized to sell that inventory? + +## Use Cases + +- **Post-campaign validation**: Verify that impressions were delivered to compliant properties +- **Supply path verification**: Confirm sales agents were authorized by publishers +- **Real-time monitoring**: Check compliance rate during campaign execution +- **Audit trails**: Generate compliance reports for regulatory or brand safety reviews + +## Request + +```json +{ + "$schema": "/schemas/property/validate-property-delivery-request.json", + "list_id": "pl_abc123", + "records": [ + { + "identifier": { "type": "domain", "value": "www.nytimes.com" }, + "impressions": 103 + }, + { + "identifier": { "type": "domain", "value": "sketchy-site.example" }, + "impressions": 47 + }, + { + "identifier": { "type": "android_package", "value": "com.unknown.app" }, + "impressions": 25 + } + ], + "include_compliant": false +} +``` + +### Parameters + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `list_id` | string | Yes | ID of the property list to validate against | +| `records` | array | Yes | Delivery records to validate (1-10,000 records) | +| `records[].identifier` | object | Yes | Property identifier (`type` and `value`) | +| `records[].impressions` | integer | Yes | Number of impressions delivered | +| `records[].record_id` | string | No | Client-provided ID for correlation | +| `records[].sales_agent_url` | string | No | Sales agent URL to validate authorization against adagents.json | +| `include_compliant` | boolean | No | Include compliant records in results (default: false) | + +## Response + +```json +{ + "$schema": "/schemas/property/validate-property-delivery-response.json", + "list_id": "pl_abc123", + "summary": { + "total_records": 4, + "total_impressions": 200, + "compliant_records": 1, + "compliant_impressions": 103, + "non_compliant_records": 1, + "non_compliant_impressions": 47, + "not_covered_records": 1, + "not_covered_impressions": 25, + "unidentified_records": 1, + "unidentified_impressions": 25 + }, + "aggregate": { + "score": 68.7, + "grade": "C+", + "label": "68.7% compliant", + "methodology_url": "https://governance.example.com/methodology/compliance-scoring" + }, + "results": [ + { + "identifier": { "type": "domain", "value": "sketchy-site.example" }, + "status": "non_compliant", + "impressions": 47, + "violations": [ + { + "code": "not_in_list", + "message": "Identifier not found in resolved property list" + } + ] + }, + { + "identifier": { "type": "domain", "value": "new-site.example" }, + "status": "not_covered", + "impressions": 25 + }, + { + "identifier": { "type": "android_package", "value": "com.unknown.app" }, + "status": "unidentified", + "impressions": 25 + } + ], + "validated_at": "2026-01-04T19:00:00Z", + "list_resolved_at": "2026-01-04T12:00:00Z" +} +``` + +### Response Fields + +| Field | Type | Description | +|-------|------|-------------| +| `list_id` | string | ID of the property list validated against | +| `summary` | object | Raw counts for property compliance validation | +| `aggregate` | object | Optional computed metrics from the governance agent | +| `results` | array | Per-record validation results | +| `validated_at` | datetime | When validation was performed | +| `list_resolved_at` | datetime | Resolution timestamp of the property list used | + +### Summary Fields + +The summary provides raw counts - consumers calculate rates as needed: + +| Field | Description | +|-------|-------------| +| `total_records` | Total records validated | +| `total_impressions` | Total impressions across all records | +| `compliant_records` / `compliant_impressions` | Records/impressions in the property list | +| `non_compliant_records` / `non_compliant_impressions` | Records/impressions NOT in the property list | +| `not_covered_records` / `not_covered_impressions` | Identifier recognized but no data available | +| `unidentified_records` / `unidentified_impressions` | Identifier type not resolvable | + +### Validation Statuses + +| Status | Meaning | +|--------|---------| +| `compliant` | Identifier is in the resolved property list | +| `non_compliant` | Identifier is NOT in the resolved property list | +| `not_covered` | Identifier recognized but governance agent has no data for it | +| `unidentified` | Identifier type not resolvable by this agent | + +## Understanding not_covered vs unidentified + +These two statuses distinguish different types of "unknown" scenarios: + +**`not_covered`** - The governance agent recognized the identifier (e.g., it's a valid domain) but doesn't have data for that specific property. This happens when: +- A property is too new to be in the agent's database +- The property exists but hasn't been evaluated yet +- The agent's coverage doesn't include that property category + +**`unidentified`** - The governance agent couldn't recognize the identifier at all. This happens when: +- Client-side detection failed to capture the property +- The identifier type isn't supported (e.g., agent handles domains but received an app ID) +- The identifier value is malformed or invalid + +Both statuses should be excluded from compliance rate calculations - you cannot penalize for detection or coverage gaps. + +## Optional Aggregate Metrics + +Governance agents can optionally return computed metrics in the `aggregate` field: + +```json +"aggregate": { + "score": 68.7, + "grade": "C+", + "label": "68.7% compliant", + "methodology_url": "https://governance.example.com/methodology" +} +``` + +| Field | Description | +|-------|-------------| +| `score` | Numeric score (scale is agent-defined, typically 0-100) | +| `grade` | Letter grade or category (e.g., "A+", "B-", "Gold") | +| `label` | Human-readable summary (e.g., "85% compliant") | +| `methodology_url` | URL explaining how the aggregate was calculated | + +The `aggregate` field is optional and agent-specific. Consumers should not assume a particular format - always check `methodology_url` for interpretation. + +## Calculating Your Own Rates + +The response always includes raw counts. Calculate rates as needed: + +```python +# Compliance rate (exclude unverifiable from denominator) +unverifiable = summary.not_covered_impressions + summary.unidentified_impressions +verifiable = summary.total_impressions - unverifiable +compliance_rate = summary.compliant_impressions / verifiable if verifiable > 0 else None +``` + +In the example above: +- Compliant impressions: 103 +- Non-compliant impressions: 47 +- not_covered + unidentified impressions: 50 (excluded) +- Compliance rate: 103 / (200 - 50) = 103 / 150 = 68.7% + +## Violation Codes + +| Code | Description | +|------|-------------| +| `not_in_list` | Identifier not found in the resolved property list | +| `excluded` | Identifier explicitly excluded via `exclude_identifiers` filter | +| `country_mismatch` | Property lacks feature data for required countries | +| `channel_mismatch` | Property doesn't support required channels | +| `feature_failed` | Property failed a `feature_requirements` filter | + +### Feature Violation Details + +When a property fails a feature requirement, the violation includes the feature details: + +```json +{ + "identifier": { "type": "domain", "value": "low-quality-site.example" }, + "status": "non_compliant", + "impressions": 150, + "violations": [ + { + "code": "feature_failed", + "message": "Property failed consent_quality requirement (min: 85)", + "feature_id": "consent_quality", + "requirement": { + "min_value": 85 + } + } + ] +} +``` + +The `feature_id` and `requirement` fields are optional - they're included when the violation is due to a feature requirement filter. + +## Supply Path Authorization + +When `sales_agent_url` is provided in delivery records, the governance agent validates that the sales agent is authorized to sell the property by checking the publisher's `adagents.json`. + +### Request with Authorization + +```json +{ + "list_id": "pl_abc123", + "records": [ + { + "identifier": { "type": "domain", "value": "www.nytimes.com" }, + "impressions": 103, + "sales_agent_url": "https://legitimate-ssp.example.com" + }, + { + "identifier": { "type": "domain", "value": "www.nytimes.com" }, + "impressions": 50, + "sales_agent_url": "https://unauthorized-reseller.example.com" + } + ] +} +``` + +### Response with Authorization + +When authorization is validated, each result includes an `authorization` field: + +```json +{ + "list_id": "pl_abc123", + "summary": { + "total_records": 2, + "total_impressions": 153, + "compliant_records": 2, + "compliant_impressions": 153, + "non_compliant_records": 0, + "non_compliant_impressions": 0, + "unknown_records": 0, + "unknown_impressions": 0 + }, + "authorization_summary": { + "records_checked": 2, + "impressions_checked": 153, + "authorized_records": 1, + "authorized_impressions": 103, + "unauthorized_records": 1, + "unauthorized_impressions": 50, + "unknown_records": 0, + "unknown_impressions": 0 + }, + "results": [ + { + "identifier": { "type": "domain", "value": "www.nytimes.com" }, + "status": "compliant", + "impressions": 50, + "authorization": { + "status": "unauthorized", + "publisher_domain": "nytimes.com", + "sales_agent_url": "https://unauthorized-reseller.example.com", + "violation": { + "code": "agent_not_authorized", + "message": "Sales agent not listed in nytimes.com/.well-known/adagents.json" + } + } + } + ], + "validated_at": "2026-01-04T19:00:00Z" +} +``` + +### Authorization Statuses + +| Status | Meaning | Included in authorization_rate? | +|--------|---------|--------------------------------| +| `authorized` | Sales agent is listed in publisher's adagents.json | Yes (numerator) | +| `unauthorized` | Sales agent is NOT listed in publisher's adagents.json | Yes (denominator only) | +| `unknown` | Could not fetch or parse adagents.json | No (excluded) | + +### Authorization Violation Codes + +| Code | Description | +|------|-------------| +| `agent_not_authorized` | Sales agent URL not found in publisher's authorized_agents list | +| `adagents_not_found` | Publisher's adagents.json could not be fetched (404, timeout, etc.) | +| `adagents_invalid` | Publisher's adagents.json exists but is malformed | +| `property_not_declared` | Property identifier not declared in publisher's adagents.json | + +### Two Independent Checks + +Property compliance and authorization are **independent checks**. A record can be: + +| Property Status | Authorization Status | Meaning | +|-----------------|---------------------|---------| +| compliant | authorized | Fully valid - property in list, sold by authorized agent | +| compliant | unauthorized | Property is approved but sold by unauthorized reseller | +| non_compliant | authorized | Authorized agent sold property outside your list | +| non_compliant | unauthorized | Neither property nor agent validated | + +Both checks use the same "unknown excludes from rate" pattern - you cannot penalize for detection gaps. + +## Best Practices + +### Batch Validation + +For large-scale validation, batch records up to the 10,000 limit: + +```python +def validate_delivery_batch(records, list_id, governance_agent): + """Validate delivery records in batches.""" + batch_size = 10000 + all_results = [] + + for i in range(0, len(records), batch_size): + batch = records[i:i + batch_size] + response = governance_agent.validate_property_delivery( + list_id=list_id, + records=batch + ) + all_results.extend(response.results) + + return all_results +``` + +### Sampling Strategy + +For real-time monitoring during campaign execution, validate a statistical sample rather than all records: + +```python +import random + +def sample_and_validate(records, sample_size=1000): + """Validate a random sample for real-time monitoring.""" + sample = random.sample(records, min(sample_size, len(records))) + return governance_agent.validate_property_delivery( + list_id=list_id, + records=sample + ) +``` + +### Handling Unknown Records + +Track unknown rates separately to identify detection gaps: + +```python +def analyze_validation(response): + """Analyze validation results with unknown handling.""" + summary = response.summary + + # Core compliance metric + compliance_rate = summary.compliance_rate + + # Detection quality metric + unknown_rate = summary.unknown_impressions / summary.total_impressions + + if unknown_rate > 0.1: + print(f"Warning: {unknown_rate:.1%} of impressions unresolvable") + + return { + "compliance_rate": compliance_rate, + "unknown_rate": unknown_rate, + "non_compliant_impressions": summary.non_compliant_impressions + } +``` + +## Related Tasks + +- [create_property_list](/docs/governance/property/tasks/property_lists#create_property_list) - Create the list to validate against +- [get_property_list](/docs/governance/property/tasks/property_lists#get_property_list) - Retrieve current list membership +- [list_property_features](/docs/governance/property/tasks/list_property_features) - Discover available filter features diff --git a/docs/media-buy/capability-discovery/index.mdx b/docs/media-buy/capability-discovery/index.mdx index 885a0e16c9..297984b4c1 100644 --- a/docs/media-buy/capability-discovery/index.mdx +++ b/docs/media-buy/capability-discovery/index.mdx @@ -21,7 +21,7 @@ Learn how sales agents can support standard creative formats through the referen - Leverage the Standard Creative Agent for standard formats - Work with publisher-specific creative agents for custom formats -### [Authorized Properties](/docs/media-buy/capability-discovery/authorized-properties) 🔐 +### [Understanding Authorization](/docs/governance/property/authorized-properties) 🔐 Learn how AdCP prevents unauthorized resale and ensures sales agents are legitimate. Understand: - The problem of unauthorized resale in digital advertising @@ -30,7 +30,7 @@ Learn how AdCP prevents unauthorized resale and ensures sales agents are legitim - Property tags and large-scale authorization management -**Cross-Protocol Foundation**: The `adagents.json` authorization system applies across ALL AdCP protocols (Media Buy, Signals, and future Curation). See the [adagents.json specification](/docs/media-buy/capability-discovery/adagents) for complete implementation details. +**Cross-Protocol Foundation**: The `adagents.json` authorization system applies across ALL AdCP protocols (Media Buy, Signals, and future Curation). See the [adagents.json specification](/docs/governance/property/adagents) for complete implementation details. @@ -80,4 +80,4 @@ Together, these capabilities provide the foundation for safe, efficient, and eff - **[Creative Protocol](/docs/creative/)** - Creative agents and manifests - **[Creative Channel Guides](/docs/creative/channels/video)** - Format examples and patterns - **[Creative Manifests](/docs/creative/creative-manifests)** - Understanding creative specifications -- **[adagents.json Specification](/docs/media-buy/capability-discovery/adagents)** - Publisher authorization system (applies across all AdCP protocols) \ No newline at end of file +- **[adagents.json Specification](/docs/governance/property/adagents)** - Publisher authorization system (applies across all AdCP protocols) \ No newline at end of file diff --git a/docs/media-buy/index.mdx b/docs/media-buy/index.mdx index 0ead41042a..ab06863c28 100644 --- a/docs/media-buy/index.mdx +++ b/docs/media-buy/index.mdx @@ -232,7 +232,7 @@ Choose your path based on your role and needs: 4. **Explore [Optimization & Reporting](/docs/media-buy/media-buys/optimization-reporting)** - Learn performance management ### **For Publishers/Sales Agents** -1. **Learn [Authorized Properties](/docs/media-buy/capability-discovery/authorized-properties)** - Understand authorization requirements +1. **Learn [Understanding Authorization](/docs/governance/property/authorized-properties)** - Understand authorization requirements 2. **Review [Creative Formats](/docs/creative/formats)** - See supported creative specifications 3. **Study [Advanced Topics](/docs/media-buy/advanced-topics/)** - Deep dive into technical implementation diff --git a/docs/media-buy/task-reference/get_products.mdx b/docs/media-buy/task-reference/get_products.mdx index 9a877d146e..fa00a940b7 100644 --- a/docs/media-buy/task-reference/get_products.mdx +++ b/docs/media-buy/task-reference/get_products.mdx @@ -129,6 +129,7 @@ asyncio.run(discover_with_filters()) | `brief` | string | No | Natural language description of campaign requirements | | `brand_manifest` | BrandManifest \| string | No | Brand information (inline object or URL). See [Brand Manifest](/docs/creative/brand-manifest) | | `filters` | Filters | No | Structured filters (see below) | +| `property_list` | PropertyListRef | No | [AdCP 3.0] Reference to a property list for filtering. See [Property Lists](/docs/governance/property/tasks/property_lists) | ### Filters Object @@ -172,6 +173,12 @@ Returns an array of `products`, each containing: | `pricing_options` | PricingOption[] | Available pricing models (CPM, CPCV, etc.) | | `brief_relevance` | string | Why this product matches the brief (when brief provided) | +### Response Metadata + +| Field | Type | Description | +|-------|------|-------------| +| `property_list_applied` | boolean | [AdCP 3.0] `true` if the agent filtered products based on the provided `property_list`. Absent or `false` if not provided or not supported. | + **See schema for complete field list**: [`get-products-response.json`](https://adcontextprotocol.org/schemas/v2/media-buy/get-products-response.json) ## Common Scenarios @@ -476,6 +483,80 @@ asyncio.run(discover_standard_formats()) +### Property List Filtering + + +**AdCP 3.0** - Property list filtering requires governance agent support. + + +Filter products to only those available on properties in your approved list: + + + +```javascript JavaScript +import { testAgent } from '@adcp/client/testing'; + +// Filter products by property list from governance agent +const result = await testAgent.getProducts({ + brief: 'Brand-safe inventory for family brand', + brand_manifest: { + name: 'Nike', + url: 'https://nike.com' + }, + property_list: { + agent_url: 'https://governance.example.com', + list_id: 'pl_brand_safe_2024' + } +}); + +if (result.success && result.data) { + // Check if filtering was actually applied + if (result.data.property_list_applied) { + console.log(`Found ${result.data.products.length} products on approved properties`); + } else { + console.log('Agent does not support property list filtering'); + console.log(`Found ${result.data.products.length} products (unfiltered)`); + } +} +``` + +```python Python +import asyncio +from adcp import test_agent + +async def discover_with_property_list(): + # Filter products by property list from governance agent + result = await test_agent.simple.get_products( + brief='Brand-safe inventory for family brand', + brand_manifest={ + 'name': 'Nike', + 'url': 'https://nike.com' + }, + property_list={ + 'agent_url': 'https://governance.example.com', + 'list_id': 'pl_brand_safe_2024' + } + ) + + # Check if filtering was actually applied + if result.get('property_list_applied'): + print(f"Found {len(result['products'])} products on approved properties") + else: + print("Agent does not support property list filtering") + print(f"Found {len(result['products'])} products (unfiltered)") + +asyncio.run(discover_with_property_list()) +``` + + + +**Note**: If `property_list_applied` is absent or `false`, the sales agent did not filter products. This can happen if: +- The agent doesn't support property governance features +- The agent couldn't access the property list +- The property list had no effect on the available inventory + +See [Property Governance](/docs/governance/property/specification) for more on property lists. + ## Error Handling | Error Code | Description | Resolution | diff --git a/docs/media-buy/task-reference/list_authorized_properties.mdx b/docs/media-buy/task-reference/list_authorized_properties.mdx index 5e7cb8ea9d..55bd3fcf87 100644 --- a/docs/media-buy/task-reference/list_authorized_properties.mdx +++ b/docs/media-buy/task-reference/list_authorized_properties.mdx @@ -498,6 +498,6 @@ After discovering authorized properties: ## Learn More -- [adagents.json Specification](/docs/media-buy/capability-discovery/adagents) - Publisher authorization file format +- [adagents.json Specification](/docs/governance/property/adagents) - Publisher authorization file format - [Property Schema](https://adcontextprotocol.org/schemas/v2/core/property.json) - Property definition structure - [Authorization Guide](/docs/reference/authentication) - How authorization works in AdCP diff --git a/docs/reference/implementor-faq.mdx b/docs/reference/implementor-faq.mdx index ce93b224df..747ada9c0c 100644 --- a/docs/reference/implementor-faq.mdx +++ b/docs/reference/implementor-faq.mdx @@ -289,7 +289,7 @@ assert(response.message.includes("policy")); 3. Verify the sales agent URL appears in `authorized_agents` 4. Reject products from unauthorized agents -See [Authorization Validation](/docs/media-buy/capability-discovery/adagents#buyer-agent-validation) for complete requirements. +See [Authorization Validation](/docs/governance/property/adagents#buyer-agent-validation) for complete requirements. ## Terminology diff --git a/docs/reference/roadmap.mdx b/docs/reference/roadmap.mdx index 35b1ec2d61..137ddeb29e 100644 --- a/docs/reference/roadmap.mdx +++ b/docs/reference/roadmap.mdx @@ -59,9 +59,9 @@ These features are in active development but may not make the 3.0 release: The following features are in the working group planning stages: -### Governance Protocol +### Governance Protocol [3.0] -A framework for multi-party approval workflows and delegated authority management. See the [Governance Protocol Working Document](https://docs.google.com/document/d/1osokTr5Xk2PyLBUHbx2jpPad0TLrQIDh2I6ZWzpHMmY/edit?tab=t.0) for details. +Property governance (property lists, filters, adagents.json authorization), brand standards (brand manifests, creative guidelines), and compliance controls. See the [Governance Protocol](/docs/governance/index) for current specification. ### Private Marketplace (PMP) Support - Deal ID integration diff --git a/package-lock.json b/package-lock.json index e3bc17f296..6cb4764f14 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "adcontextprotocol", - "version": "2.5.2", + "version": "2.6.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "adcontextprotocol", - "version": "2.5.2", + "version": "2.6.0", "dependencies": { "@adcp/client": "^3.5.2", "@anthropic-ai/sdk": "^0.71.2", diff --git a/static/schemas/source/adagents.json b/static/schemas/source/adagents.json index 286aee996f..bc48225ca6 100644 --- a/static/schemas/source/adagents.json +++ b/static/schemas/source/adagents.json @@ -264,6 +264,38 @@ "type": "string", "format": "date-time", "description": "ISO 8601 timestamp indicating when this file was last updated" + }, + "property_features": { + "type": "array", + "description": "[AdCP 3.0] Optional list of agents that provide property feature data (certifications, scores, compliance status). Used for discovery - actual data comes from querying the agent's get_property_features task.", + "items": { + "type": "object", + "properties": { + "url": { + "type": "string", + "format": "uri", + "description": "The agent's API endpoint URL (must implement get_property_features)" + }, + "name": { + "type": "string", + "description": "Human-readable name of the vendor/agent (e.g., 'Scope3', 'TAG', 'OneTrust')" + }, + "features": { + "type": "array", + "description": "Feature IDs this agent provides (e.g., 'carbon_score', 'tag_certified_against_fraud'). Use list_property_features on the agent for full definitions.", + "items": { + "type": "string" + }, + "minItems": 1 + }, + "publisher_id": { + "type": "string", + "description": "Optional publisher identifier at this agent (for lookup)" + } + }, + "required": ["url", "name", "features"], + "additionalProperties": true + } } }, "required": [ @@ -489,6 +521,66 @@ } ], "last_updated": "2025-01-10T17:00:00Z" + }, + { + "$schema": "/schemas/adagents.json", + "contact": { + "name": "Premium News Publisher", + "email": "adops@news.example.com", + "domain": "news.example.com" + }, + "properties": [ + { + "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-safe 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.scope3.com", + "name": "Scope3", + "features": ["carbon_score", "sustainability_grade"], + "publisher_id": "pub_news_12345" + }, + { + "url": "https://api.tagtoday.net", + "name": "TAG", + "features": ["tag_certified_against_fraud", "tag_brand_safety_certified"] + }, + { + "url": "https://api.onetrust.com", + "name": "OneTrust", + "features": ["gdpr_compliant", "tcf_registered", "ccpa_compliant"], + "publisher_id": "ot_news_67890" + } + ], + "last_updated": "2025-01-10T18:00:00Z" } ] } diff --git a/static/schemas/source/core/identifier.json b/static/schemas/source/core/identifier.json new file mode 100644 index 0000000000..f7e68aabe2 --- /dev/null +++ b/static/schemas/source/core/identifier.json @@ -0,0 +1,19 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/core/identifier.json", + "title": "Identifier", + "description": "A property identifier with type and value. Used to identify properties across platforms (domains, app store IDs, etc.).", + "type": "object", + "properties": { + "type": { + "$ref": "/schemas/enums/identifier-types.json", + "description": "Type of identifier" + }, + "value": { + "type": "string", + "description": "The identifier value. For domain type: 'example.com' matches base domain plus www and m subdomains; 'edition.example.com' matches that specific subdomain; '*.example.com' matches ALL subdomains but NOT base domain" + } + }, + "required": ["type", "value"], + "additionalProperties": false +} diff --git a/static/schemas/source/core/property-list-ref.json b/static/schemas/source/core/property-list-ref.json new file mode 100644 index 0000000000..06e5ced9ba --- /dev/null +++ b/static/schemas/source/core/property-list-ref.json @@ -0,0 +1,25 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/core/property-list-ref.json", + "title": "Property List Reference", + "description": "Reference to an externally managed property list. Enables passing large property sets (50,000+) without embedding them in requests. The receiving agent fetches and caches the list independently.", + "type": "object", + "properties": { + "agent_url": { + "type": "string", + "format": "uri", + "description": "URL of the agent managing the property list" + }, + "list_id": { + "type": "string", + "description": "Identifier for the property list within the agent", + "minLength": 1 + }, + "auth_token": { + "type": "string", + "description": "JWT or other authorization token for accessing the list. Optional if the list is public or caller has implicit access." + } + }, + "required": ["agent_url", "list_id"], + "additionalProperties": false +} diff --git a/static/schemas/source/enums/adcp-domain.json b/static/schemas/source/enums/adcp-domain.json index 68db230066..ee392aeff0 100644 --- a/static/schemas/source/enums/adcp-domain.json +++ b/static/schemas/source/enums/adcp-domain.json @@ -4,8 +4,11 @@ "title": "AdCP Domain", "description": "AdCP protocol domains for task categorization", "type": "string", - "enum": [ - "media-buy", - "signals" - ] + "enum": ["media-buy", "signals", "governance", "creative"], + "enumDescriptions": { + "media-buy": "Campaign creation, package management, and delivery optimization", + "signals": "Audience signal discovery and activation", + "governance": "Property governance (identity, authorization, data, selection), brand standards, and compliance", + "creative": "Creative asset management, format discovery, and rendering" + } } diff --git a/static/schemas/source/enums/task-type.json b/static/schemas/source/enums/task-type.json index 063291bb42..7af80e9b9d 100644 --- a/static/schemas/source/enums/task-type.json +++ b/static/schemas/source/enums/task-type.json @@ -9,18 +9,30 @@ "update_media_buy", "sync_creatives", "activate_signal", - "get_signals" + "get_signals", + "list_property_features", + "create_property_list", + "update_property_list", + "get_property_list", + "list_property_lists", + "delete_property_list" ], "enumDescriptions": { "create_media_buy": "Media-buy domain: Create a new advertising campaign with one or more packages", "update_media_buy": "Media-buy domain: Update campaign settings, package configuration, or delivery parameters", "sync_creatives": "Media-buy domain: Sync creative assets to publisher's library with upsert semantics", "activate_signal": "Signals domain: Activate an audience signal on a specific platform or account", - "get_signals": "Signals domain: Discover available audience signals based on natural language description" + "get_signals": "Signals domain: Discover available audience signals based on natural language description", + "list_property_features": "Property domain: Discover what features a governance agent can evaluate", + "create_property_list": "Property domain: Create a new property list with filters and brand manifest", + "update_property_list": "Property domain: Update an existing property list", + "get_property_list": "Property domain: Retrieve a property list with resolved properties", + "list_property_lists": "Property domain: List all accessible property lists", + "delete_property_list": "Property domain: Delete a property list" }, "notes": [ "Task types map to specific AdCP task operations", - "Each task type belongs to either the 'media-buy' or 'signals' domain", + "Each task type belongs to the 'media-buy', 'signals', 'property', or 'creative' domain", "This enum is used in task management APIs (tasks/list, tasks/get) and webhook payloads", "New task types require a minor version bump per semantic versioning" ] diff --git a/static/schemas/source/index.json b/static/schemas/source/index.json index 7a0db1fbd7..635683aced 100644 --- a/static/schemas/source/index.json +++ b/static/schemas/source/index.json @@ -168,6 +168,14 @@ "property-tag": { "$ref": "/schemas/core/property-tag.json", "description": "Tag for categorizing publisher properties - lowercase alphanumeric with underscores only" + }, + "property-list-ref": { + "$ref": "/schemas/core/property-list-ref.json", + "description": "Reference to an externally managed property list for passing large property sets" + }, + "identifier": { + "$ref": "/schemas/core/identifier.json", + "description": "A property identifier with type and value" } } }, @@ -220,7 +228,7 @@ }, "task-type": { "$ref": "/schemas/enums/task-type.json", - "description": "Valid AdCP task types across all domains (create_media_buy, update_media_buy, sync_creatives, activate_signal, get_signals)" + "description": "Valid AdCP task types across all domains (create_media_buy, update_media_buy, sync_creatives, activate_signal, get_signals, list_property_features, create_property_list, get_property_list, update_property_list, delete_property_list)" }, "asset-content-type": { "$ref": "/schemas/enums/asset-content-type.json", @@ -280,7 +288,7 @@ }, "adcp-domain": { "$ref": "/schemas/enums/adcp-domain.json", - "description": "AdCP protocol domains (media-buy, signals)" + "description": "AdCP protocol domains (media-buy, signals, governance)" }, "http-method": { "$ref": "/schemas/enums/http-method.json", @@ -562,6 +570,105 @@ } } }, + "governance": { + "description": "Governance protocol for property governance, brand standards, and compliance", + "supporting-schemas": { + "property-feature-definition": { + "$ref": "/schemas/property/property-feature-definition.json", + "description": "Definition of a feature that a governance agent can evaluate" + }, + "property-feature": { + "$ref": "/schemas/property/property-feature.json", + "description": "A discrete feature assessment for a property" + }, + "feature-requirement": { + "$ref": "/schemas/property/feature-requirement.json", + "description": "A feature-based requirement for property filtering" + }, + "property-error": { + "$ref": "/schemas/property/property-error.json", + "description": "Error information for a property that could not be evaluated" + }, + "property-list": { + "$ref": "/schemas/property/property-list.json", + "description": "A managed property list with optional filters for dynamic evaluation" + }, + "property-list-filters": { + "$ref": "/schemas/property/property-list-filters.json", + "description": "Filters that dynamically modify a property list when resolved" + }, + "property-list-changed-webhook": { + "$ref": "/schemas/property/property-list-changed-webhook.json", + "description": "Webhook payload when a property list changes" + }, + "base-property-source": { + "$ref": "/schemas/property/base-property-source.json", + "description": "A source of properties for a property list - supports publisher+tags, publisher+property_ids, or direct identifiers" + } + }, + "tasks": { + "list-property-features": { + "request": { + "$ref": "/schemas/property/list-property-features-request.json", + "description": "Request parameters for discovering governance agent capabilities" + }, + "response": { + "$ref": "/schemas/property/list-property-features-response.json", + "description": "Response payload for list_property_features task" + } + }, + "create-property-list": { + "request": { + "$ref": "/schemas/property/create-property-list-request.json", + "description": "Request parameters for creating a new property list" + }, + "response": { + "$ref": "/schemas/property/create-property-list-response.json", + "description": "Response payload for create_property_list task" + } + }, + "update-property-list": { + "request": { + "$ref": "/schemas/property/update-property-list-request.json", + "description": "Request parameters for updating an existing property list" + }, + "response": { + "$ref": "/schemas/property/update-property-list-response.json", + "description": "Response payload for update_property_list task" + } + }, + "get-property-list": { + "request": { + "$ref": "/schemas/property/get-property-list-request.json", + "description": "Request parameters for retrieving a property list with resolved properties" + }, + "response": { + "$ref": "/schemas/property/get-property-list-response.json", + "description": "Response payload for get_property_list task" + } + }, + "list-property-lists": { + "request": { + "$ref": "/schemas/property/list-property-lists-request.json", + "description": "Request parameters for listing property lists" + }, + "response": { + "$ref": "/schemas/property/list-property-lists-response.json", + "description": "Response payload for list_property_lists task" + } + }, + "delete-property-list": { + "request": { + "$ref": "/schemas/property/delete-property-list-request.json", + "description": "Request parameters for deleting a property list" + }, + "response": { + "$ref": "/schemas/property/delete-property-list-response.json", + "description": "Response payload for delete_property_list task" + } + } + } + }, "adagents": { "description": "Authorized sales agents file format specification", "$ref": "/schemas/adagents.json", diff --git a/static/schemas/source/media-buy/get-products-request.json b/static/schemas/source/media-buy/get-products-request.json index 1c7483fd84..02817c0f38 100644 --- a/static/schemas/source/media-buy/get-products-request.json +++ b/static/schemas/source/media-buy/get-products-request.json @@ -16,6 +16,10 @@ "filters": { "$ref": "/schemas/core/product-filters.json" }, + "property_list": { + "$ref": "/schemas/core/property-list-ref.json", + "description": "[AdCP 3.0] Reference to an externally managed property list. When provided, the sales agent should filter products to only those available on properties in the list." + }, "context": { "$ref": "/schemas/core/context.json" }, diff --git a/static/schemas/source/media-buy/get-products-response.json b/static/schemas/source/media-buy/get-products-response.json index 3a54bd3c8e..692787b91c 100644 --- a/static/schemas/source/media-buy/get-products-response.json +++ b/static/schemas/source/media-buy/get-products-response.json @@ -19,6 +19,10 @@ "$ref": "/schemas/core/error.json" } }, + "property_list_applied": { + "type": "boolean", + "description": "[AdCP 3.0] Indicates whether property_list filtering was applied. True if the agent filtered products based on the provided property_list. Absent or false if property_list was not provided or not supported by this agent." + }, "context": { "$ref": "/schemas/core/context.json" }, diff --git a/static/schemas/source/property/authorization-result.json b/static/schemas/source/property/authorization-result.json new file mode 100644 index 0000000000..48187649fc --- /dev/null +++ b/static/schemas/source/property/authorization-result.json @@ -0,0 +1,41 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/property/authorization-result.json", + "title": "Authorization Result", + "description": "Result of validating sales agent authorization for a property. Checks if the sales agent is listed in the property's adagents.json.", + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": ["authorized", "unauthorized", "unknown"], + "description": "Authorization status: authorized (agent in adagents.json), unauthorized (agent not in adagents.json), unknown (could not fetch or parse adagents.json)" + }, + "publisher_domain": { + "type": "string", + "description": "The publisher domain where adagents.json was checked" + }, + "sales_agent_url": { + "type": "string", + "format": "uri", + "description": "The sales agent URL that was validated" + }, + "violation": { + "type": "object", + "description": "Details about the authorization failure (only present for unauthorized status)", + "properties": { + "code": { + "type": "string", + "description": "Machine-readable violation code" + }, + "message": { + "type": "string", + "description": "Human-readable violation description" + } + }, + "required": ["code", "message"], + "additionalProperties": false + } + }, + "required": ["status"], + "additionalProperties": false +} diff --git a/static/schemas/source/property/base-property-source.json b/static/schemas/source/property/base-property-source.json new file mode 100644 index 0000000000..d23b0c2bc3 --- /dev/null +++ b/static/schemas/source/property/base-property-source.json @@ -0,0 +1,87 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/property/base-property-source.json", + "title": "Base Property Source", + "description": "A source of properties for a property list. Supports three selection patterns: publisher with tags, publisher with property IDs, or direct identifiers.", + "discriminator": { + "propertyName": "selection_type" + }, + "oneOf": [ + { + "type": "object", + "title": "Publisher Tags Source", + "description": "Select properties from a publisher by tag membership", + "properties": { + "selection_type": { + "type": "string", + "const": "publisher_tags", + "description": "Discriminator indicating selection by property tags within a publisher" + }, + "publisher_domain": { + "type": "string", + "description": "Domain where publisher's adagents.json is hosted (e.g., 'raptive.com')", + "pattern": "^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$" + }, + "tags": { + "type": "array", + "description": "Property tags from the publisher's adagents.json. Selects all properties with these tags.", + "items": { + "$ref": "/schemas/core/property-tag.json" + }, + "minItems": 1 + } + }, + "required": ["selection_type", "publisher_domain", "tags"], + "additionalProperties": false + }, + { + "type": "object", + "title": "Publisher Property IDs Source", + "description": "Select specific properties from a publisher by ID", + "properties": { + "selection_type": { + "type": "string", + "const": "publisher_ids", + "description": "Discriminator indicating selection by specific property IDs within a publisher" + }, + "publisher_domain": { + "type": "string", + "description": "Domain where publisher's adagents.json is hosted (e.g., 'raptive.com')", + "pattern": "^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$" + }, + "property_ids": { + "type": "array", + "description": "Specific property IDs from the publisher's adagents.json", + "items": { + "$ref": "/schemas/core/property-id.json" + }, + "minItems": 1 + } + }, + "required": ["selection_type", "publisher_domain", "property_ids"], + "additionalProperties": false + }, + { + "type": "object", + "title": "Direct Identifiers Source", + "description": "Select properties by direct identifiers (domains, app IDs, etc.) without publisher context", + "properties": { + "selection_type": { + "type": "string", + "const": "identifiers", + "description": "Discriminator indicating selection by direct identifiers" + }, + "identifiers": { + "type": "array", + "description": "Direct property identifiers (domains, app IDs, etc.)", + "items": { + "$ref": "/schemas/core/identifier.json" + }, + "minItems": 1 + } + }, + "required": ["selection_type", "identifiers"], + "additionalProperties": false + } + ] +} diff --git a/static/schemas/source/property/create-property-list-request.json b/static/schemas/source/property/create-property-list-request.json new file mode 100644 index 0000000000..b1c3185f11 --- /dev/null +++ b/static/schemas/source/property/create-property-list-request.json @@ -0,0 +1,40 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/property/create-property-list-request.json", + "title": "Create Property List Request", + "description": "Request parameters for creating a new property list", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Human-readable name for the list" + }, + "description": { + "type": "string", + "description": "Description of the list's purpose" + }, + "base_properties": { + "type": "array", + "description": "Array of property sources to evaluate. Each entry is a discriminated union: publisher_tags (publisher_domain + tags), publisher_ids (publisher_domain + property_ids), or identifiers (direct identifiers). If omitted, queries the agent's entire property database.", + "items": { + "$ref": "/schemas/property/base-property-source.json" + } + }, + "filters": { + "$ref": "/schemas/property/property-list-filters.json", + "description": "Dynamic filters to apply when resolving the list" + }, + "brand_manifest": { + "$ref": "/schemas/core/brand-manifest.json", + "description": "Brand identity and requirements. When provided, the agent automatically applies appropriate rules based on brand characteristics (industry, target_audience, etc.)." + }, + "context": { + "$ref": "/schemas/core/context.json" + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "required": ["name"], + "additionalProperties": false +} diff --git a/static/schemas/source/property/create-property-list-response.json b/static/schemas/source/property/create-property-list-response.json new file mode 100644 index 0000000000..2b608088db --- /dev/null +++ b/static/schemas/source/property/create-property-list-response.json @@ -0,0 +1,22 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/property/create-property-list-response.json", + "title": "Create Property List Response", + "description": "Response payload for create_property_list task", + "type": "object", + "properties": { + "list": { + "$ref": "/schemas/property/property-list.json", + "description": "The created property list" + }, + "auth_token": { + "type": "string", + "description": "Token that can be shared with sellers to authorize fetching this list. Store this - it is only returned at creation time." + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "required": ["list", "auth_token"], + "additionalProperties": false +} diff --git a/static/schemas/source/property/delete-property-list-request.json b/static/schemas/source/property/delete-property-list-request.json new file mode 100644 index 0000000000..0e5217d260 --- /dev/null +++ b/static/schemas/source/property/delete-property-list-request.json @@ -0,0 +1,21 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/property/delete-property-list-request.json", + "title": "Delete Property List Request", + "description": "Request parameters for deleting a property list", + "type": "object", + "properties": { + "list_id": { + "type": "string", + "description": "ID of the property list to delete" + }, + "context": { + "$ref": "/schemas/core/context.json" + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "required": ["list_id"], + "additionalProperties": false +} diff --git a/static/schemas/source/property/delete-property-list-response.json b/static/schemas/source/property/delete-property-list-response.json new file mode 100644 index 0000000000..655bbed524 --- /dev/null +++ b/static/schemas/source/property/delete-property-list-response.json @@ -0,0 +1,22 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/property/delete-property-list-response.json", + "title": "Delete Property List Response", + "description": "Response payload for delete_property_list task", + "type": "object", + "properties": { + "deleted": { + "type": "boolean", + "description": "Whether the list was successfully deleted" + }, + "list_id": { + "type": "string", + "description": "ID of the deleted list" + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "required": ["deleted", "list_id"], + "additionalProperties": false +} diff --git a/static/schemas/source/property/delivery-record.json b/static/schemas/source/property/delivery-record.json new file mode 100644 index 0000000000..29e6bc17a7 --- /dev/null +++ b/static/schemas/source/property/delivery-record.json @@ -0,0 +1,32 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/property/delivery-record.json", + "title": "Delivery Record", + "description": "A single delivery record representing impressions served to a property identifier. Used as input to validate_property_delivery.", + "type": "object", + "properties": { + "identifier": { + "$ref": "/schemas/core/identifier.json", + "description": "The property identifier where impressions were delivered" + }, + "impressions": { + "type": "integer", + "minimum": 0, + "description": "Number of impressions delivered to this identifier" + }, + "record_id": { + "type": "string", + "description": "Optional client-provided ID for correlating results back to source data" + }, + "sales_agent_url": { + "type": "string", + "format": "uri", + "description": "URL of the sales agent that sold this inventory. If provided, authorization is validated against the property's adagents.json." + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "required": ["identifier", "impressions"], + "additionalProperties": false +} diff --git a/static/schemas/source/property/feature-requirement.json b/static/schemas/source/property/feature-requirement.json new file mode 100644 index 0000000000..0a75a1a21f --- /dev/null +++ b/static/schemas/source/property/feature-requirement.json @@ -0,0 +1,34 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/property/feature-requirement.json", + "title": "Feature Requirement", + "description": "A feature-based requirement for property filtering. Use min_value/max_value for quantitative features, allowed_values for binary/categorical features.", + "type": "object", + "properties": { + "feature_id": { + "type": "string", + "description": "Feature to evaluate (discovered via list_property_features)" + }, + "min_value": { + "type": "number", + "description": "Minimum numeric value required (for quantitative features)" + }, + "max_value": { + "type": "number", + "description": "Maximum numeric value allowed (for quantitative features)" + }, + "allowed_values": { + "type": "array", + "description": "Values that pass the requirement (for binary/categorical features)", + "items": {} + }, + "if_not_covered": { + "type": "string", + "enum": ["exclude", "include"], + "default": "exclude", + "description": "How to handle properties where this feature is not covered. 'exclude' (default): property is removed from the list. 'include': property passes this requirement (fail-open)." + } + }, + "required": ["feature_id"], + "additionalProperties": false +} diff --git a/static/schemas/source/property/get-property-features-request.json b/static/schemas/source/property/get-property-features-request.json new file mode 100644 index 0000000000..a664eb65a9 --- /dev/null +++ b/static/schemas/source/property/get-property-features-request.json @@ -0,0 +1,68 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/property/get-property-features-request.json", + "title": "Get Property Features Request", + "description": "Request payload for get_property_features task. Retrieves feature values for properties from a governance agent. Supports two modes: explicit property list OR publisher-based discovery.", + "type": "object", + "properties": { + "properties": { + "type": "array", + "description": "Explicit list of properties to get features for. Can be domain strings or structured property references. Use this when you know exactly which properties you want.", + "items": { + "oneOf": [ + { + "type": "string", + "description": "Domain string (e.g., 'example.com')" + }, + { + "$ref": "/schemas/core/property-id.json" + } + ] + }, + "minItems": 1, + "maxItems": 100 + }, + "publisher_domain": { + "type": "string", + "description": "Publisher domain to discover properties for. Use this to get features for all properties belonging to a publisher. Can be combined with property_types and property_tags for filtering." + }, + "property_types": { + "type": "array", + "description": "Filter to specific property types (e.g., 'website', 'mobile_app', 'ctv_app'). Only applies when using publisher_domain.", + "items": { + "$ref": "/schemas/enums/property-type.json" + } + }, + "property_tags": { + "type": "array", + "description": "Filter to properties with these tags. Only applies when using publisher_domain.", + "items": { + "$ref": "/schemas/core/property-tag.json" + } + }, + "feature_ids": { + "type": "array", + "description": "Optional filter to specific features. If omitted, returns all available features.", + "items": { + "type": "string" + } + }, + "context": { + "$ref": "/schemas/core/context.json" + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "oneOf": [ + { + "required": ["properties"], + "description": "Explicit property list mode" + }, + { + "required": ["publisher_domain"], + "description": "Publisher discovery mode" + } + ], + "additionalProperties": false +} diff --git a/static/schemas/source/property/get-property-features-response.json b/static/schemas/source/property/get-property-features-response.json new file mode 100644 index 0000000000..d07a0d480d --- /dev/null +++ b/static/schemas/source/property/get-property-features-response.json @@ -0,0 +1,28 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/property/get-property-features-response.json", + "title": "Get Property Features Response", + "description": "Response payload for get_property_features task. Returns feature values for requested properties.", + "type": "object", + "properties": { + "results": { + "type": "array", + "description": "Feature values for each requested property", + "items": { + "$ref": "/schemas/property/property-feature-result.json" + } + }, + "errors": { + "type": "array", + "description": "Errors for properties that could not be processed", + "items": { + "$ref": "/schemas/core/error.json" + } + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "required": ["results"], + "additionalProperties": false +} diff --git a/static/schemas/source/property/get-property-list-request.json b/static/schemas/source/property/get-property-list-request.json new file mode 100644 index 0000000000..1fd852a761 --- /dev/null +++ b/static/schemas/source/property/get-property-list-request.json @@ -0,0 +1,35 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/property/get-property-list-request.json", + "title": "Get Property List Request", + "description": "Request parameters for retrieving a property list with resolved identifiers", + "type": "object", + "properties": { + "list_id": { + "type": "string", + "description": "ID of the property list to retrieve" + }, + "resolve": { + "type": "boolean", + "description": "Whether to apply filters and return resolved identifiers (default: true)", + "default": true + }, + "max_results": { + "type": "integer", + "description": "Maximum identifiers to return (for large lists)", + "minimum": 1 + }, + "cursor": { + "type": "string", + "description": "Pagination cursor for large result sets" + }, + "context": { + "$ref": "/schemas/core/context.json" + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "required": ["list_id"], + "additionalProperties": false +} diff --git a/static/schemas/source/property/get-property-list-response.json b/static/schemas/source/property/get-property-list-response.json new file mode 100644 index 0000000000..89ba3bfc5c --- /dev/null +++ b/static/schemas/source/property/get-property-list-response.json @@ -0,0 +1,68 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/property/get-property-list-response.json", + "title": "Get Property List Response", + "description": "Response payload for get_property_list task. Returns identifiers only (not full property objects or scores). Consumers should cache the resolved identifiers and refresh based on cache_valid_until.", + "type": "object", + "properties": { + "list": { + "$ref": "/schemas/property/property-list.json", + "description": "The property list metadata (always returned)" + }, + "identifiers": { + "type": "array", + "description": "Resolved identifiers that passed filters (if resolve=true). Cache these locally for real-time use.", + "items": { + "$ref": "/schemas/core/identifier.json" + } + }, + "total_count": { + "type": "integer", + "description": "Total number of identifiers in resolved list" + }, + "returned_count": { + "type": "integer", + "description": "Number of identifiers returned in this response" + }, + "pagination": { + "type": "object", + "description": "Pagination information", + "properties": { + "has_more": { + "type": "boolean", + "description": "Whether more results are available" + }, + "cursor": { + "type": "string", + "description": "Cursor for next page" + } + }, + "additionalProperties": false + }, + "resolved_at": { + "type": "string", + "format": "date-time", + "description": "When the list was resolved" + }, + "cache_valid_until": { + "type": "string", + "format": "date-time", + "description": "Cache expiration timestamp. Re-fetch the list after this time to get updated identifiers." + }, + "coverage_gaps": { + "type": "object", + "description": "Properties included in the list despite missing feature data. Only present when a feature_requirement has if_not_covered='include'. Maps feature_id to list of identifiers not covered for that feature.", + "additionalProperties": { + "type": "array", + "items": { + "$ref": "/schemas/core/identifier.json" + } + } + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "required": ["list"], + "additionalProperties": false +} diff --git a/static/schemas/source/property/list-property-features-request.json b/static/schemas/source/property/list-property-features-request.json new file mode 100644 index 0000000000..3c16d096c1 --- /dev/null +++ b/static/schemas/source/property/list-property-features-request.json @@ -0,0 +1,27 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/property/list-property-features-request.json", + "title": "List Property Features Request", + "description": "Request payload for list_property_features task. Discovers what features a governance agent can evaluate.", + "type": "object", + "properties": { + "property_types": { + "type": "array", + "description": "Filter to features available for these property types", + "items": { + "type": "string" + } + }, + "countries": { + "type": "array", + "description": "Filter to features available in these countries", + "items": { + "type": "string" + } + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "additionalProperties": false +} diff --git a/static/schemas/source/property/list-property-features-response.json b/static/schemas/source/property/list-property-features-response.json new file mode 100644 index 0000000000..efbf849fd4 --- /dev/null +++ b/static/schemas/source/property/list-property-features-response.json @@ -0,0 +1,21 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/property/list-property-features-response.json", + "title": "List Property Features Response", + "description": "Response payload for list_property_features task. Returns the features this governance agent can evaluate.", + "type": "object", + "properties": { + "features": { + "type": "array", + "description": "Features this agent can evaluate", + "items": { + "$ref": "/schemas/property/property-feature-definition.json" + } + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "required": ["features"], + "additionalProperties": false +} diff --git a/static/schemas/source/property/list-property-lists-request.json b/static/schemas/source/property/list-property-lists-request.json new file mode 100644 index 0000000000..034c38e475 --- /dev/null +++ b/static/schemas/source/property/list-property-lists-request.json @@ -0,0 +1,34 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/property/list-property-lists-request.json", + "title": "List Property Lists Request", + "description": "Request parameters for listing property lists", + "type": "object", + "properties": { + "principal": { + "type": "string", + "description": "Filter to lists owned by this principal" + }, + "name_contains": { + "type": "string", + "description": "Filter to lists whose name contains this string" + }, + "max_results": { + "type": "integer", + "description": "Maximum lists to return", + "minimum": 1, + "default": 100 + }, + "cursor": { + "type": "string", + "description": "Pagination cursor" + }, + "context": { + "$ref": "/schemas/core/context.json" + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "additionalProperties": false +} diff --git a/static/schemas/source/property/list-property-lists-response.json b/static/schemas/source/property/list-property-lists-response.json new file mode 100644 index 0000000000..f80b67ed17 --- /dev/null +++ b/static/schemas/source/property/list-property-lists-response.json @@ -0,0 +1,44 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/property/list-property-lists-response.json", + "title": "List Property Lists Response", + "description": "Response payload for list_property_lists task", + "type": "object", + "properties": { + "lists": { + "type": "array", + "description": "Array of property lists (metadata only, not resolved properties)", + "items": { + "$ref": "/schemas/property/property-list.json" + } + }, + "total_count": { + "type": "integer", + "description": "Total number of lists matching criteria" + }, + "returned_count": { + "type": "integer", + "description": "Number of lists returned in this response" + }, + "pagination": { + "type": "object", + "description": "Pagination information", + "properties": { + "has_more": { + "type": "boolean", + "description": "Whether more results are available" + }, + "cursor": { + "type": "string", + "description": "Cursor for next page" + } + }, + "additionalProperties": false + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "required": ["lists"], + "additionalProperties": false +} diff --git a/static/schemas/source/property/property-error.json b/static/schemas/source/property/property-error.json new file mode 100644 index 0000000000..7b46b096ef --- /dev/null +++ b/static/schemas/source/property/property-error.json @@ -0,0 +1,31 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/property/property-error.json", + "title": "Property Error", + "description": "Error information for a property that could not be evaluated", + "type": "object", + "properties": { + "code": { + "type": "string", + "description": "Error code", + "enum": [ + "PROPERTY_NOT_FOUND", + "PROPERTY_NOT_MONITORED", + "LIST_NOT_FOUND", + "LIST_ACCESS_DENIED", + "METHODOLOGY_NOT_SUPPORTED", + "JURISDICTION_NOT_SUPPORTED" + ] + }, + "property": { + "$ref": "/schemas/core/property.json", + "description": "The property that caused the error" + }, + "message": { + "type": "string", + "description": "Human-readable error message" + } + }, + "required": ["code", "message"], + "additionalProperties": false +} diff --git a/static/schemas/source/property/property-feature-definition.json b/static/schemas/source/property/property-feature-definition.json new file mode 100644 index 0000000000..baaf017bb7 --- /dev/null +++ b/static/schemas/source/property/property-feature-definition.json @@ -0,0 +1,84 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/property/property-feature-definition.json", + "title": "Property Feature Definition", + "description": "Defines a feature that a governance agent can evaluate for properties. Used in list_property_features to advertise agent capabilities.", + "type": "object", + "properties": { + "feature_id": { + "type": "string", + "description": "Unique identifier for this feature (e.g., 'consent_quality', 'carbon_score', 'coppa_certified')" + }, + "name": { + "type": "string", + "description": "Human-readable name for the feature" + }, + "description": { + "type": "string", + "description": "Description of what this feature measures or represents" + }, + "type": { + "type": "string", + "enum": ["binary", "quantitative", "categorical"], + "description": "The type of values this feature produces: binary (true/false), quantitative (numeric range), categorical (enumerated values)" + }, + "range": { + "type": "object", + "description": "For quantitative features, the valid range of values", + "properties": { + "min": { + "type": "number", + "description": "Minimum value" + }, + "max": { + "type": "number", + "description": "Maximum value" + } + }, + "required": ["min", "max"], + "additionalProperties": false + }, + "allowed_values": { + "type": "array", + "description": "For categorical features, the set of valid values", + "items": { + "type": "string" + } + }, + "coverage": { + "type": "object", + "description": "What this feature covers (empty arrays = all)", + "properties": { + "property_types": { + "type": "array", + "description": "Property types this feature applies to", + "items": { + "type": "string" + } + }, + "countries": { + "type": "array", + "description": "Countries where this feature is available", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + }, + "methodology_url": { + "type": "string", + "format": "uri", + "description": "URL to documentation explaining how this feature is calculated/measured" + }, + "methodology_version": { + "type": "string", + "description": "Version identifier for the methodology (for audit trails)" + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "required": ["feature_id", "name", "type", "methodology_url"], + "additionalProperties": false +} diff --git a/static/schemas/source/property/property-feature-result.json b/static/schemas/source/property/property-feature-result.json new file mode 100644 index 0000000000..25a43a6439 --- /dev/null +++ b/static/schemas/source/property/property-feature-result.json @@ -0,0 +1,43 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/property/property-feature-result.json", + "title": "Property Feature Result", + "description": "Feature values for a single property from a governance agent.", + "type": "object", + "properties": { + "property": { + "oneOf": [ + { + "type": "string", + "description": "Domain string (e.g., 'example.com')" + }, + { + "$ref": "/schemas/core/property-id.json" + } + ], + "description": "The property these features apply to" + }, + "features": { + "type": "object", + "description": "Map of feature_id to feature value", + "additionalProperties": { + "$ref": "/schemas/property/property-feature-value.json" + } + }, + "coverage_status": { + "type": "string", + "enum": ["covered", "not_covered", "pending"], + "description": "Whether this property is covered by this governance agent: covered (has data), not_covered (not measured), pending (measurement in progress)" + }, + "last_evaluated": { + "type": "string", + "format": "date-time", + "description": "When features were last evaluated for this property" + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "required": ["property", "coverage_status"], + "additionalProperties": false +} diff --git a/static/schemas/source/property/property-feature-value.json b/static/schemas/source/property/property-feature-value.json new file mode 100644 index 0000000000..c2b70ab712 --- /dev/null +++ b/static/schemas/source/property/property-feature-value.json @@ -0,0 +1,51 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/property/property-feature-value.json", + "title": "Property Feature Value", + "description": "A single feature value for a property. Structure varies by feature type (binary, quantitative, categorical).", + "type": "object", + "properties": { + "value": { + "description": "The feature value. Type depends on feature definition: boolean for binary, number for quantitative, string for categorical.", + "oneOf": [ + { "type": "boolean" }, + { "type": "number" }, + { "type": "string" } + ] + }, + "unit": { + "type": "string", + "description": "Unit of measurement for quantitative values (e.g., 'gCO2e/1000_impressions', 'percentage')" + }, + "confidence": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "Confidence score for this value (0-1)" + }, + "measured_at": { + "type": "string", + "format": "date-time", + "description": "When this specific value was measured" + }, + "expires_at": { + "type": "string", + "format": "date-time", + "description": "When this certification/value expires (for time-limited certifications)" + }, + "methodology_version": { + "type": "string", + "description": "Version of the methodology used to calculate this value" + }, + "details": { + "type": "object", + "description": "Additional vendor-specific details about this measurement", + "additionalProperties": true + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "required": ["value"], + "additionalProperties": false +} diff --git a/static/schemas/source/property/property-feature.json b/static/schemas/source/property/property-feature.json new file mode 100644 index 0000000000..6c9939b595 --- /dev/null +++ b/static/schemas/source/property/property-feature.json @@ -0,0 +1,23 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/property/property-feature.json", + "title": "Property Feature", + "description": "A discrete feature assessment for a property (e.g., from app store privacy labels)", + "type": "object", + "properties": { + "feature_id": { + "type": "string", + "description": "Identifier for the feature being assessed" + }, + "value": { + "type": "string", + "description": "The feature value" + }, + "source": { + "type": "string", + "description": "Source of the feature data (e.g., app_store_privacy_label, tcf_string)" + } + }, + "required": ["feature_id", "value"], + "additionalProperties": false +} diff --git a/static/schemas/source/property/property-list-changed-webhook.json b/static/schemas/source/property/property-list-changed-webhook.json new file mode 100644 index 0000000000..69b6c8f17f --- /dev/null +++ b/static/schemas/source/property/property-list-changed-webhook.json @@ -0,0 +1,60 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/property/property-list-changed-webhook.json", + "title": "Property List Changed Webhook", + "description": "Webhook notification sent when a property list's resolved properties change. Contains a summary only - recipients must call get_property_list to retrieve the updated properties. This keeps payloads small and avoids redundant data transfer.", + "type": "object", + "properties": { + "event": { + "type": "string", + "const": "property_list_changed", + "description": "The event type" + }, + "list_id": { + "type": "string", + "description": "ID of the property list that changed" + }, + "list_name": { + "type": "string", + "description": "Name of the property list" + }, + "change_summary": { + "type": "object", + "description": "Summary of changes to the resolved list", + "properties": { + "properties_added": { + "type": "integer", + "description": "Number of properties added since last resolution" + }, + "properties_removed": { + "type": "integer", + "description": "Number of properties removed since last resolution" + }, + "total_properties": { + "type": "integer", + "description": "Total properties in the resolved list" + } + }, + "additionalProperties": false + }, + "resolved_at": { + "type": "string", + "format": "date-time", + "description": "When the list was re-resolved" + }, + "cache_valid_until": { + "type": "string", + "format": "date-time", + "description": "When the consumer should refresh from the governance agent" + }, + "signature": { + "type": "string", + "description": "Cryptographic signature of the webhook payload, signed with the agent's private key. Recipients MUST verify this signature." + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "required": ["event", "list_id", "resolved_at", "signature"], + "additionalProperties": false +} diff --git a/static/schemas/source/property/property-list-filters.json b/static/schemas/source/property/property-list-filters.json new file mode 100644 index 0000000000..ec132f2bf3 --- /dev/null +++ b/static/schemas/source/property/property-list-filters.json @@ -0,0 +1,47 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/property/property-list-filters.json", + "title": "Property List Filters", + "description": "Filters that dynamically modify a property list when resolved", + "type": "object", + "properties": { + "countries_all": { + "type": "array", + "description": "Property must have feature data for ALL listed countries (ISO codes). Required.", + "items": { + "type": "string", + "pattern": "^[A-Z]{2}$" + } + }, + "channels_any": { + "type": "array", + "description": "Property must support ANY of the listed channels. Required.", + "items": { + "$ref": "/schemas/enums/channels.json" + } + }, + "property_types": { + "type": "array", + "description": "Filter to these property types", + "items": { + "$ref": "/schemas/enums/property-type.json" + } + }, + "feature_requirements": { + "type": "array", + "description": "Feature-based requirements. Property must pass ALL requirements (AND logic).", + "items": { + "$ref": "/schemas/property/feature-requirement.json" + } + }, + "exclude_identifiers": { + "type": "array", + "description": "Identifiers to always exclude from results", + "items": { + "$ref": "/schemas/core/identifier.json" + } + } + }, + "required": ["countries_all", "channels_any"], + "additionalProperties": false +} diff --git a/static/schemas/source/property/property-list.json b/static/schemas/source/property/property-list.json new file mode 100644 index 0000000000..53a89a5cf3 --- /dev/null +++ b/static/schemas/source/property/property-list.json @@ -0,0 +1,67 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/property/property-list.json", + "title": "Property List", + "description": "A managed property list with optional filters for dynamic evaluation. Lists are resolved at setup time and cached by orchestrators/sellers for real-time use.", + "type": "object", + "properties": { + "list_id": { + "type": "string", + "description": "Unique identifier for this property list" + }, + "name": { + "type": "string", + "description": "Human-readable name for the list" + }, + "description": { + "type": "string", + "description": "Description of the list's purpose" + }, + "principal": { + "type": "string", + "description": "Principal identity that owns this list" + }, + "base_properties": { + "type": "array", + "description": "Array of property sources to evaluate. Each entry is a discriminated union: publisher_tags (publisher_domain + tags), publisher_ids (publisher_domain + property_ids), or identifiers (direct identifiers). If omitted, queries the agent's entire property database.", + "items": { + "$ref": "/schemas/property/base-property-source.json" + } + }, + "filters": { + "$ref": "/schemas/property/property-list-filters.json", + "description": "Dynamic filters applied when resolving the list" + }, + "brand_manifest": { + "$ref": "/schemas/core/brand-manifest.json", + "description": "Brand identity used to automatically apply appropriate rules" + }, + "webhook_url": { + "type": "string", + "format": "uri", + "description": "URL to receive notifications when the resolved list changes" + }, + "cache_duration_hours": { + "type": "integer", + "description": "Recommended cache duration for resolved list. Consumers should re-fetch after this period.", + "minimum": 1, + "default": 24 + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "When the list was created" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "description": "When the list was last modified" + }, + "property_count": { + "type": "integer", + "description": "Number of properties in the resolved list (at time of last resolution)" + } + }, + "required": ["list_id", "name"], + "additionalProperties": false +} diff --git a/static/schemas/source/property/update-property-list-request.json b/static/schemas/source/property/update-property-list-request.json new file mode 100644 index 0000000000..d83cdb49b0 --- /dev/null +++ b/static/schemas/source/property/update-property-list-request.json @@ -0,0 +1,49 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/property/update-property-list-request.json", + "title": "Update Property List Request", + "description": "Request parameters for updating an existing property list", + "type": "object", + "properties": { + "list_id": { + "type": "string", + "description": "ID of the property list to update" + }, + "name": { + "type": "string", + "description": "New name for the list" + }, + "description": { + "type": "string", + "description": "New description" + }, + "base_properties": { + "type": "array", + "description": "Complete replacement for the base properties list (not a patch). Each entry is a discriminated union: publisher_tags (publisher_domain + tags), publisher_ids (publisher_domain + property_ids), or identifiers (direct identifiers).", + "items": { + "$ref": "/schemas/property/base-property-source.json" + } + }, + "filters": { + "$ref": "/schemas/property/property-list-filters.json", + "description": "Complete replacement for the filters (not a patch)" + }, + "brand_manifest": { + "$ref": "/schemas/core/brand-manifest.json", + "description": "Update brand identity and requirements" + }, + "webhook_url": { + "type": "string", + "format": "uri", + "description": "Update the webhook URL for list change notifications (set to empty string to remove)" + }, + "context": { + "$ref": "/schemas/core/context.json" + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "required": ["list_id"], + "additionalProperties": false +} diff --git a/static/schemas/source/property/update-property-list-response.json b/static/schemas/source/property/update-property-list-response.json new file mode 100644 index 0000000000..8258df259c --- /dev/null +++ b/static/schemas/source/property/update-property-list-response.json @@ -0,0 +1,18 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/property/update-property-list-response.json", + "title": "Update Property List Response", + "description": "Response payload for update_property_list task", + "type": "object", + "properties": { + "list": { + "$ref": "/schemas/property/property-list.json", + "description": "The updated property list" + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "required": ["list"], + "additionalProperties": false +} diff --git a/static/schemas/source/property/validate-property-delivery-request.json b/static/schemas/source/property/validate-property-delivery-request.json new file mode 100644 index 0000000000..16597cf433 --- /dev/null +++ b/static/schemas/source/property/validate-property-delivery-request.json @@ -0,0 +1,32 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/property/validate-property-delivery-request.json", + "title": "Validate Property Delivery Request", + "description": "Request payload for validate_property_delivery task. Validates delivery records against a property list to determine compliance.", + "type": "object", + "properties": { + "list_id": { + "type": "string", + "description": "ID of the property list to validate against" + }, + "records": { + "type": "array", + "description": "Delivery records to validate. Each record represents impressions delivered to a property identifier.", + "items": { + "$ref": "/schemas/property/delivery-record.json" + }, + "minItems": 1, + "maxItems": 10000 + }, + "include_compliant": { + "type": "boolean", + "default": false, + "description": "Include compliant records in results (default: only return non_compliant, unmodeled, and unidentified)" + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "required": ["list_id", "records"], + "additionalProperties": false +} diff --git a/static/schemas/source/property/validate-property-delivery-response.json b/static/schemas/source/property/validate-property-delivery-response.json new file mode 100644 index 0000000000..be229f4067 --- /dev/null +++ b/static/schemas/source/property/validate-property-delivery-response.json @@ -0,0 +1,167 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/property/validate-property-delivery-response.json", + "title": "Validate Property Delivery Response", + "description": "Response payload for validate_property_delivery task. Returns aggregate compliance statistics and per-record validation results.", + "type": "object", + "properties": { + "list_id": { + "type": "string", + "description": "ID of the property list validated against" + }, + "summary": { + "type": "object", + "description": "Aggregate validation statistics", + "properties": { + "total_records": { + "type": "integer", + "description": "Total number of records validated" + }, + "total_impressions": { + "type": "integer", + "description": "Total impressions across all records" + }, + "compliant_records": { + "type": "integer", + "description": "Number of records with compliant status" + }, + "compliant_impressions": { + "type": "integer", + "description": "Impressions from compliant records" + }, + "non_compliant_records": { + "type": "integer", + "description": "Number of records with non_compliant status" + }, + "non_compliant_impressions": { + "type": "integer", + "description": "Impressions from non_compliant records" + }, + "not_covered_records": { + "type": "integer", + "description": "Number of records where identifier was recognized but no data available" + }, + "not_covered_impressions": { + "type": "integer", + "description": "Impressions from not_covered records" + }, + "unidentified_records": { + "type": "integer", + "description": "Number of records where identifier type was not resolvable" + }, + "unidentified_impressions": { + "type": "integer", + "description": "Impressions from unidentified records" + } + }, + "required": [ + "total_records", + "total_impressions", + "compliant_records", + "compliant_impressions", + "non_compliant_records", + "non_compliant_impressions", + "not_covered_records", + "not_covered_impressions", + "unidentified_records", + "unidentified_impressions" + ], + "additionalProperties": false + }, + "aggregate": { + "type": "object", + "description": "Optional aggregate measurements computed by the governance agent. Format and meaning are agent-specific.", + "properties": { + "score": { + "type": "number", + "description": "Numeric score (0-100 scale typical, but agent-defined)" + }, + "grade": { + "type": "string", + "description": "Letter grade or category (e.g., 'A+', 'B-', 'Gold', 'Compliant')" + }, + "label": { + "type": "string", + "description": "Human-readable summary (e.g., '85% compliant', 'High quality')" + }, + "methodology_url": { + "type": "string", + "format": "uri", + "description": "URL explaining how this aggregate was calculated" + } + }, + "additionalProperties": true + }, + "authorization_summary": { + "type": "object", + "description": "Aggregate authorization statistics. Only present if any records included sales_agent_url.", + "properties": { + "records_checked": { + "type": "integer", + "description": "Number of records with sales_agent_url provided" + }, + "impressions_checked": { + "type": "integer", + "description": "Total impressions from records with sales_agent_url" + }, + "authorized_records": { + "type": "integer", + "description": "Number of records where sales agent was authorized" + }, + "authorized_impressions": { + "type": "integer", + "description": "Impressions from authorized records" + }, + "unauthorized_records": { + "type": "integer", + "description": "Number of records where sales agent was NOT authorized" + }, + "unauthorized_impressions": { + "type": "integer", + "description": "Impressions from unauthorized records" + }, + "unknown_records": { + "type": "integer", + "description": "Number of records where authorization could not be determined (adagents.json unavailable)" + }, + "unknown_impressions": { + "type": "integer", + "description": "Impressions from records where authorization could not be determined" + } + }, + "required": [ + "records_checked", + "impressions_checked", + "authorized_records", + "authorized_impressions", + "unauthorized_records", + "unauthorized_impressions", + "unknown_records", + "unknown_impressions" + ], + "additionalProperties": false + }, + "results": { + "type": "array", + "description": "Per-record validation results. By default only includes non_compliant and unknown records. Set include_compliant=true to include all records.", + "items": { + "$ref": "/schemas/property/validation-result.json" + } + }, + "validated_at": { + "type": "string", + "format": "date-time", + "description": "Timestamp when validation was performed" + }, + "list_resolved_at": { + "type": "string", + "format": "date-time", + "description": "Timestamp of the property list resolution used for validation" + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "required": ["list_id", "summary", "results", "validated_at"], + "additionalProperties": false +} diff --git a/static/schemas/source/property/validation-result.json b/static/schemas/source/property/validation-result.json new file mode 100644 index 0000000000..b11db55aef --- /dev/null +++ b/static/schemas/source/property/validation-result.json @@ -0,0 +1,79 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/property/validation-result.json", + "title": "Validation Result", + "description": "Result of validating a single delivery record against a property list.", + "type": "object", + "properties": { + "identifier": { + "$ref": "/schemas/core/identifier.json", + "description": "The identifier that was validated" + }, + "record_id": { + "type": "string", + "description": "Client-provided ID from the delivery record (if provided)" + }, + "status": { + "type": "string", + "enum": ["compliant", "non_compliant", "not_covered", "unidentified"], + "description": "Validation status: compliant (in list), non_compliant (not in list), not_covered (identifier recognized but no data available), unidentified (identifier type not resolvable by this governance agent)" + }, + "impressions": { + "type": "integer", + "minimum": 0, + "description": "Number of impressions from this record" + }, + "violations": { + "type": "array", + "description": "Specific violations found (only present for non_compliant records)", + "items": { + "type": "object", + "properties": { + "code": { + "type": "string", + "description": "Machine-readable violation code" + }, + "message": { + "type": "string", + "description": "Human-readable violation description" + }, + "feature_id": { + "type": "string", + "description": "ID of the feature that caused the violation (only present for feature_failed violations)" + }, + "requirement": { + "type": "object", + "description": "The feature requirement that was not met (only present for feature_failed violations)", + "properties": { + "min_value": { + "type": "number", + "description": "Minimum value that was required" + }, + "max_value": { + "type": "number", + "description": "Maximum value that was allowed" + }, + "allowed_values": { + "type": "array", + "description": "Values that would have been acceptable", + "items": {} + } + }, + "additionalProperties": false + } + }, + "required": ["code", "message"], + "additionalProperties": false + } + }, + "authorization": { + "$ref": "/schemas/property/authorization-result.json", + "description": "Authorization validation result (only present if sales_agent_url was provided in the delivery record)" + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "required": ["identifier", "status", "impressions"], + "additionalProperties": false +} diff --git a/v2.6-rc/docs/media-buy/capability-discovery/authorized-properties.mdx b/v2.6-rc/docs/media-buy/capability-discovery/authorized-properties.mdx index 11d72b671c..13264accab 100644 --- a/v2.6-rc/docs/media-buy/capability-discovery/authorized-properties.mdx +++ b/v2.6-rc/docs/media-buy/capability-discovery/authorized-properties.mdx @@ -268,11 +268,11 @@ For complete technical details on implementing the `adagents.json` file format, - Validation code examples and error handling - Security considerations and best practices -See the **[adagents.json Tech Spec](/docs/media-buy/capability-discovery/adagents)** for complete implementation guidance. +See the **[adagents.json Tech Spec](/docs/governance/property/adagents)** for complete implementation guidance. ## Related Documentation - **[`list_authorized_properties`](/docs/media-buy/task-reference/list_authorized_properties)** - API reference for property discovery - **[Product Discovery](/docs/media-buy/product-discovery/)** - How authorization integrates with product discovery - **[Properties Schema](https://adcontextprotocol.org/schemas/v2/core/property.json)** - Technical property data model -- **[adagents.json Tech Spec](/docs/media-buy/capability-discovery/adagents)** - Complete `adagents.json` implementation guide \ No newline at end of file +- **[adagents.json Tech Spec](/docs/governance/property/adagents)** - Complete `adagents.json` implementation guide \ No newline at end of file diff --git a/v2.6-rc/docs/media-buy/capability-discovery/index.mdx b/v2.6-rc/docs/media-buy/capability-discovery/index.mdx index 885a0e16c9..214806a992 100644 --- a/v2.6-rc/docs/media-buy/capability-discovery/index.mdx +++ b/v2.6-rc/docs/media-buy/capability-discovery/index.mdx @@ -21,7 +21,7 @@ Learn how sales agents can support standard creative formats through the referen - Leverage the Standard Creative Agent for standard formats - Work with publisher-specific creative agents for custom formats -### [Authorized Properties](/docs/media-buy/capability-discovery/authorized-properties) 🔐 +### [Authorized Properties](/docs/governance/property/authorized-properties) 🔐 Learn how AdCP prevents unauthorized resale and ensures sales agents are legitimate. Understand: - The problem of unauthorized resale in digital advertising @@ -30,7 +30,7 @@ Learn how AdCP prevents unauthorized resale and ensures sales agents are legitim - Property tags and large-scale authorization management -**Cross-Protocol Foundation**: The `adagents.json` authorization system applies across ALL AdCP protocols (Media Buy, Signals, and future Curation). See the [adagents.json specification](/docs/media-buy/capability-discovery/adagents) for complete implementation details. +**Cross-Protocol Foundation**: The `adagents.json` authorization system applies across ALL AdCP protocols (Media Buy, Signals, and future Curation). See the [adagents.json specification](/docs/governance/property/adagents) for complete implementation details. @@ -80,4 +80,4 @@ Together, these capabilities provide the foundation for safe, efficient, and eff - **[Creative Protocol](/docs/creative/)** - Creative agents and manifests - **[Creative Channel Guides](/docs/creative/channels/video)** - Format examples and patterns - **[Creative Manifests](/docs/creative/creative-manifests)** - Understanding creative specifications -- **[adagents.json Specification](/docs/media-buy/capability-discovery/adagents)** - Publisher authorization system (applies across all AdCP protocols) \ No newline at end of file +- **[adagents.json Specification](/docs/governance/property/adagents)** - Publisher authorization system (applies across all AdCP protocols) \ No newline at end of file diff --git a/v2.6-rc/docs/media-buy/index.mdx b/v2.6-rc/docs/media-buy/index.mdx index 0ead41042a..fcaed419b0 100644 --- a/v2.6-rc/docs/media-buy/index.mdx +++ b/v2.6-rc/docs/media-buy/index.mdx @@ -232,7 +232,7 @@ Choose your path based on your role and needs: 4. **Explore [Optimization & Reporting](/docs/media-buy/media-buys/optimization-reporting)** - Learn performance management ### **For Publishers/Sales Agents** -1. **Learn [Authorized Properties](/docs/media-buy/capability-discovery/authorized-properties)** - Understand authorization requirements +1. **Learn [Authorized Properties](/docs/governance/property/authorized-properties)** - Understand authorization requirements 2. **Review [Creative Formats](/docs/creative/formats)** - See supported creative specifications 3. **Study [Advanced Topics](/docs/media-buy/advanced-topics/)** - Deep dive into technical implementation diff --git a/v2.6-rc/docs/media-buy/task-reference/list_authorized_properties.mdx b/v2.6-rc/docs/media-buy/task-reference/list_authorized_properties.mdx index 5e7cb8ea9d..55bd3fcf87 100644 --- a/v2.6-rc/docs/media-buy/task-reference/list_authorized_properties.mdx +++ b/v2.6-rc/docs/media-buy/task-reference/list_authorized_properties.mdx @@ -498,6 +498,6 @@ After discovering authorized properties: ## Learn More -- [adagents.json Specification](/docs/media-buy/capability-discovery/adagents) - Publisher authorization file format +- [adagents.json Specification](/docs/governance/property/adagents) - Publisher authorization file format - [Property Schema](https://adcontextprotocol.org/schemas/v2/core/property.json) - Property definition structure - [Authorization Guide](/docs/reference/authentication) - How authorization works in AdCP diff --git a/v2.6-rc/docs/reference/implementor-faq.mdx b/v2.6-rc/docs/reference/implementor-faq.mdx index ce93b224df..747ada9c0c 100644 --- a/v2.6-rc/docs/reference/implementor-faq.mdx +++ b/v2.6-rc/docs/reference/implementor-faq.mdx @@ -289,7 +289,7 @@ assert(response.message.includes("policy")); 3. Verify the sales agent URL appears in `authorized_agents` 4. Reject products from unauthorized agents -See [Authorization Validation](/docs/media-buy/capability-discovery/adagents#buyer-agent-validation) for complete requirements. +See [Authorization Validation](/docs/governance/property/adagents#buyer-agent-validation) for complete requirements. ## Terminology From c453bc5f3e9e1cb96dada4c72a873b0a1319d329 Mon Sep 17 00:00:00 2001 From: BaiyuScope3 Date: Tue, 13 Jan 2026 18:32:58 -0500 Subject: [PATCH 17/34] build: rebuild dist/schemas/2.6.0 with impressions and paused fields Includes: - impressions field in package-request.json and update-media-buy-request.json - paused field in package-request.json - Other pending schema updates from 2.6.x source --- dist/schemas/2.6.0/adagents.json | 92 ++++++++++ .../media-buy/build-creative-request.json | 2 +- .../media-buy/build-creative-response.json | 2 +- .../media-buy/create-media-buy-request.json | 12 +- .../media-buy/create-media-buy-response.json | 2 +- .../get-media-buy-delivery-request.json | 2 +- .../get-media-buy-delivery-response.json | 2 +- .../media-buy/get-products-request.json | 28 ++- .../media-buy/get-products-response.json | 6 +- .../list-authorized-properties-request.json | 2 +- .../list-authorized-properties-response.json | 2 +- .../list-creative-formats-request.json | 2 +- .../list-creative-formats-response.json | 2 +- .../media-buy/list-creatives-request.json | 2 +- .../media-buy/list-creatives-response.json | 2 +- .../bundled/media-buy/package-request.json | 12 +- .../provide-performance-feedback-request.json | 2 +- ...provide-performance-feedback-response.json | 2 +- .../media-buy/sync-creatives-request.json | 2 +- .../media-buy/sync-creatives-response.json | 2 +- .../media-buy/update-media-buy-request.json | 7 +- .../media-buy/update-media-buy-response.json | 2 +- .../signals/activate-signal-request.json | 2 +- .../signals/activate-signal-response.json | 2 +- .../bundled/signals/get-signals-request.json | 2 +- .../bundled/signals/get-signals-response.json | 2 +- dist/schemas/2.6.0/core/identifier.json | 19 ++ .../schemas/2.6.0/core/property-list-ref.json | 25 +++ .../2.6.0/creative/asset-types/index.json | 2 +- dist/schemas/2.6.0/enums/adcp-domain.json | 11 +- dist/schemas/2.6.0/enums/task-type.json | 18 +- .../2.6.0/extensions/extension-meta.json | 59 +++++++ dist/schemas/2.6.0/extensions/index.json | 9 + dist/schemas/2.6.0/index.json | 127 ++++++++++++- .../2.6.0/media-buy/get-products-request.json | 4 + .../media-buy/get-products-response.json | 4 + .../2.6.0/media-buy/package-request.json | 10 ++ .../media-buy/update-media-buy-request.json | 5 + .../2.6.0/property/authorization-result.json | 41 +++++ .../2.6.0/property/base-property-source.json | 87 +++++++++ .../create-property-list-request.json | 40 +++++ .../create-property-list-response.json | 22 +++ .../delete-property-list-request.json | 21 +++ .../delete-property-list-response.json | 22 +++ .../2.6.0/property/delivery-record.json | 32 ++++ .../2.6.0/property/feature-requirement.json | 34 ++++ .../get-property-features-request.json | 68 +++++++ .../get-property-features-response.json | 28 +++ .../property/get-property-list-request.json | 35 ++++ .../property/get-property-list-response.json | 68 +++++++ .../list-property-features-request.json | 27 +++ .../list-property-features-response.json | 21 +++ .../property/list-property-lists-request.json | 34 ++++ .../list-property-lists-response.json | 44 +++++ .../2.6.0/property/property-error.json | 31 ++++ .../property/property-feature-definition.json | 84 +++++++++ .../property/property-feature-result.json | 43 +++++ .../property/property-feature-value.json | 51 ++++++ .../2.6.0/property/property-feature.json | 23 +++ .../property-list-changed-webhook.json | 60 +++++++ .../2.6.0/property/property-list-filters.json | 47 +++++ .../schemas/2.6.0/property/property-list.json | 67 +++++++ .../update-property-list-request.json | 49 +++++ .../update-property-list-response.json | 18 ++ .../validate-property-delivery-request.json | 32 ++++ .../validate-property-delivery-response.json | 167 ++++++++++++++++++ .../2.6.0/property/validation-result.json | 79 +++++++++ .../2.6.0/protocols/adcp-extension.json | 16 +- 68 files changed, 1841 insertions(+), 40 deletions(-) create mode 100644 dist/schemas/2.6.0/core/identifier.json create mode 100644 dist/schemas/2.6.0/core/property-list-ref.json create mode 100644 dist/schemas/2.6.0/extensions/extension-meta.json create mode 100644 dist/schemas/2.6.0/extensions/index.json create mode 100644 dist/schemas/2.6.0/property/authorization-result.json create mode 100644 dist/schemas/2.6.0/property/base-property-source.json create mode 100644 dist/schemas/2.6.0/property/create-property-list-request.json create mode 100644 dist/schemas/2.6.0/property/create-property-list-response.json create mode 100644 dist/schemas/2.6.0/property/delete-property-list-request.json create mode 100644 dist/schemas/2.6.0/property/delete-property-list-response.json create mode 100644 dist/schemas/2.6.0/property/delivery-record.json create mode 100644 dist/schemas/2.6.0/property/feature-requirement.json create mode 100644 dist/schemas/2.6.0/property/get-property-features-request.json create mode 100644 dist/schemas/2.6.0/property/get-property-features-response.json create mode 100644 dist/schemas/2.6.0/property/get-property-list-request.json create mode 100644 dist/schemas/2.6.0/property/get-property-list-response.json create mode 100644 dist/schemas/2.6.0/property/list-property-features-request.json create mode 100644 dist/schemas/2.6.0/property/list-property-features-response.json create mode 100644 dist/schemas/2.6.0/property/list-property-lists-request.json create mode 100644 dist/schemas/2.6.0/property/list-property-lists-response.json create mode 100644 dist/schemas/2.6.0/property/property-error.json create mode 100644 dist/schemas/2.6.0/property/property-feature-definition.json create mode 100644 dist/schemas/2.6.0/property/property-feature-result.json create mode 100644 dist/schemas/2.6.0/property/property-feature-value.json create mode 100644 dist/schemas/2.6.0/property/property-feature.json create mode 100644 dist/schemas/2.6.0/property/property-list-changed-webhook.json create mode 100644 dist/schemas/2.6.0/property/property-list-filters.json create mode 100644 dist/schemas/2.6.0/property/property-list.json create mode 100644 dist/schemas/2.6.0/property/update-property-list-request.json create mode 100644 dist/schemas/2.6.0/property/update-property-list-response.json create mode 100644 dist/schemas/2.6.0/property/validate-property-delivery-request.json create mode 100644 dist/schemas/2.6.0/property/validate-property-delivery-response.json create mode 100644 dist/schemas/2.6.0/property/validation-result.json diff --git a/dist/schemas/2.6.0/adagents.json b/dist/schemas/2.6.0/adagents.json index 4fafdaa844..f8f88a7be8 100644 --- a/dist/schemas/2.6.0/adagents.json +++ b/dist/schemas/2.6.0/adagents.json @@ -264,6 +264,38 @@ "type": "string", "format": "date-time", "description": "ISO 8601 timestamp indicating when this file was last updated" + }, + "property_features": { + "type": "array", + "description": "[AdCP 3.0] Optional list of agents that provide property feature data (certifications, scores, compliance status). Used for discovery - actual data comes from querying the agent's get_property_features task.", + "items": { + "type": "object", + "properties": { + "url": { + "type": "string", + "format": "uri", + "description": "The agent's API endpoint URL (must implement get_property_features)" + }, + "name": { + "type": "string", + "description": "Human-readable name of the vendor/agent (e.g., 'Scope3', 'TAG', 'OneTrust')" + }, + "features": { + "type": "array", + "description": "Feature IDs this agent provides (e.g., 'carbon_score', 'tag_certified_against_fraud'). Use list_property_features on the agent for full definitions.", + "items": { + "type": "string" + }, + "minItems": 1 + }, + "publisher_id": { + "type": "string", + "description": "Optional publisher identifier at this agent (for lookup)" + } + }, + "required": ["url", "name", "features"], + "additionalProperties": true + } } }, "required": [ @@ -489,6 +521,66 @@ } ], "last_updated": "2025-01-10T17:00:00Z" + }, + { + "$schema": "/schemas/2.6.0/adagents.json", + "contact": { + "name": "Premium News Publisher", + "email": "adops@news.example.com", + "domain": "news.example.com" + }, + "properties": [ + { + "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-safe 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.scope3.com", + "name": "Scope3", + "features": ["carbon_score", "sustainability_grade"], + "publisher_id": "pub_news_12345" + }, + { + "url": "https://api.tagtoday.net", + "name": "TAG", + "features": ["tag_certified_against_fraud", "tag_brand_safety_certified"] + }, + { + "url": "https://api.onetrust.com", + "name": "OneTrust", + "features": ["gdpr_compliant", "tcf_registered", "ccpa_compliant"], + "publisher_id": "ot_news_67890" + } + ], + "last_updated": "2025-01-10T18:00:00Z" } ] } diff --git a/dist/schemas/2.6.0/bundled/media-buy/build-creative-request.json b/dist/schemas/2.6.0/bundled/media-buy/build-creative-request.json index add3c1ba85..47860690c1 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/build-creative-request.json +++ b/dist/schemas/2.6.0/bundled/media-buy/build-creative-request.json @@ -1343,7 +1343,7 @@ ], "additionalProperties": true, "_bundled": { - "generatedAt": "2026-01-07T19:56:54.823Z", + "generatedAt": "2026-01-13T23:32:36.212Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/build-creative-response.json b/dist/schemas/2.6.0/bundled/media-buy/build-creative-response.json index d3b8342b62..ea6e61cedb 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/build-creative-response.json +++ b/dist/schemas/2.6.0/bundled/media-buy/build-creative-response.json @@ -1377,7 +1377,7 @@ } ], "_bundled": { - "generatedAt": "2026-01-07T19:56:54.825Z", + "generatedAt": "2026-01-13T23:32:36.213Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/create-media-buy-request.json b/dist/schemas/2.6.0/bundled/media-buy/create-media-buy-request.json index 9b5f26e79c..4b8eeb36e8 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/create-media-buy-request.json +++ b/dist/schemas/2.6.0/bundled/media-buy/create-media-buy-request.json @@ -104,6 +104,16 @@ "description": "Bid price for auction-based CPM pricing (required if using cpm-auction-option)", "minimum": 0 }, + "impressions": { + "type": "number", + "description": "Impression goal for this package", + "minimum": 0 + }, + "paused": { + "type": "boolean", + "description": "Whether this package should be created in a paused state. Paused packages do not deliver impressions. Defaults to false.", + "default": false + }, "targeting_overlay": { "title": "Targeting Overlay", "description": "Optional geographic refinements for media buys. Most targeting should be expressed in the brief and handled by the publisher. These fields are primarily for geographic restrictions (RCT testing, regulatory compliance).", @@ -2009,7 +2019,7 @@ ], "additionalProperties": true, "_bundled": { - "generatedAt": "2026-01-07T19:56:54.826Z", + "generatedAt": "2026-01-13T23:32:36.215Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/create-media-buy-response.json b/dist/schemas/2.6.0/bundled/media-buy/create-media-buy-response.json index 8d99b96e93..e88aeb9d3b 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/create-media-buy-response.json +++ b/dist/schemas/2.6.0/bundled/media-buy/create-media-buy-response.json @@ -350,7 +350,7 @@ } ], "_bundled": { - "generatedAt": "2026-01-07T19:56:54.827Z", + "generatedAt": "2026-01-13T23:32:36.216Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/get-media-buy-delivery-request.json b/dist/schemas/2.6.0/bundled/media-buy/get-media-buy-delivery-request.json index 26de332bc0..d06ada53f5 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/get-media-buy-delivery-request.json +++ b/dist/schemas/2.6.0/bundled/media-buy/get-media-buy-delivery-request.json @@ -86,7 +86,7 @@ }, "additionalProperties": true, "_bundled": { - "generatedAt": "2026-01-07T19:56:54.827Z", + "generatedAt": "2026-01-13T23:32:36.216Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/get-media-buy-delivery-response.json b/dist/schemas/2.6.0/bundled/media-buy/get-media-buy-delivery-response.json index e0053adb76..a5d1a44f9e 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/get-media-buy-delivery-response.json +++ b/dist/schemas/2.6.0/bundled/media-buy/get-media-buy-delivery-response.json @@ -694,7 +694,7 @@ ], "additionalProperties": true, "_bundled": { - "generatedAt": "2026-01-07T19:56:54.828Z", + "generatedAt": "2026-01-13T23:32:36.216Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/get-products-request.json b/dist/schemas/2.6.0/bundled/media-buy/get-products-request.json index 63d7d0ab1f..1d9a99867c 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/get-products-request.json +++ b/dist/schemas/2.6.0/bundled/media-buy/get-products-request.json @@ -635,6 +635,32 @@ }, "additionalProperties": true }, + "property_list": { + "title": "Property List Reference", + "description": "[AdCP 3.0] Reference to an externally managed property list. When provided, the sales agent should filter products to only those available on properties in the list.", + "type": "object", + "properties": { + "agent_url": { + "type": "string", + "format": "uri", + "description": "URL of the agent managing the property list" + }, + "list_id": { + "type": "string", + "description": "Identifier for the property list within the agent", + "minLength": 1 + }, + "auth_token": { + "type": "string", + "description": "JWT or other authorization token for accessing the list. Optional if the list is public or caller has implicit access." + } + }, + "required": [ + "agent_url", + "list_id" + ], + "additionalProperties": false + }, "context": { "title": "Context Object", "description": "Opaque correlation data that is echoed unchanged in responses. Used for internal tracking, UI session IDs, trace IDs, and other caller-specific identifiers that don't affect protocol behavior. Context data is never parsed by AdCP agents - it's simply preserved and returned.", @@ -651,7 +677,7 @@ "required": [], "additionalProperties": true, "_bundled": { - "generatedAt": "2026-01-07T19:56:54.829Z", + "generatedAt": "2026-01-13T23:32:36.217Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/get-products-response.json b/dist/schemas/2.6.0/bundled/media-buy/get-products-response.json index b0599f53d8..9b5ca4db25 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/get-products-response.json +++ b/dist/schemas/2.6.0/bundled/media-buy/get-products-response.json @@ -1289,6 +1289,10 @@ "additionalProperties": true } }, + "property_list_applied": { + "type": "boolean", + "description": "[AdCP 3.0] Indicates whether property_list filtering was applied. True if the agent filtered products based on the provided property_list. Absent or false if property_list was not provided or not supported by this agent." + }, "context": { "title": "Context Object", "description": "Opaque correlation data that is echoed unchanged in responses. Used for internal tracking, UI session IDs, trace IDs, and other caller-specific identifiers that don't affect protocol behavior. Context data is never parsed by AdCP agents - it's simply preserved and returned.", @@ -1307,7 +1311,7 @@ ], "additionalProperties": true, "_bundled": { - "generatedAt": "2026-01-07T19:56:54.830Z", + "generatedAt": "2026-01-13T23:32:36.218Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/list-authorized-properties-request.json b/dist/schemas/2.6.0/bundled/media-buy/list-authorized-properties-request.json index 7e4e17f7cf..d73f077c31 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/list-authorized-properties-request.json +++ b/dist/schemas/2.6.0/bundled/media-buy/list-authorized-properties-request.json @@ -30,7 +30,7 @@ }, "additionalProperties": true, "_bundled": { - "generatedAt": "2026-01-07T19:56:54.830Z", + "generatedAt": "2026-01-13T23:32:36.219Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/list-authorized-properties-response.json b/dist/schemas/2.6.0/bundled/media-buy/list-authorized-properties-response.json index 6ae624ec4f..58f94bfd58 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/list-authorized-properties-response.json +++ b/dist/schemas/2.6.0/bundled/media-buy/list-authorized-properties-response.json @@ -122,7 +122,7 @@ ], "additionalProperties": true, "_bundled": { - "generatedAt": "2026-01-07T19:56:54.831Z", + "generatedAt": "2026-01-13T23:32:36.219Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/list-creative-formats-request.json b/dist/schemas/2.6.0/bundled/media-buy/list-creative-formats-request.json index d02fc863f7..6ab40d589b 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/list-creative-formats-request.json +++ b/dist/schemas/2.6.0/bundled/media-buy/list-creative-formats-request.json @@ -131,7 +131,7 @@ }, "additionalProperties": true, "_bundled": { - "generatedAt": "2026-01-07T19:56:54.831Z", + "generatedAt": "2026-01-13T23:32:36.219Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/list-creative-formats-response.json b/dist/schemas/2.6.0/bundled/media-buy/list-creative-formats-response.json index ed691f6fa6..536e1ab3b5 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/list-creative-formats-response.json +++ b/dist/schemas/2.6.0/bundled/media-buy/list-creative-formats-response.json @@ -792,7 +792,7 @@ ], "additionalProperties": true, "_bundled": { - "generatedAt": "2026-01-07T19:56:54.832Z", + "generatedAt": "2026-01-13T23:32:36.219Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/list-creatives-request.json b/dist/schemas/2.6.0/bundled/media-buy/list-creatives-request.json index 319341183d..b0b34dbd74 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/list-creatives-request.json +++ b/dist/schemas/2.6.0/bundled/media-buy/list-creatives-request.json @@ -288,7 +288,7 @@ } ], "_bundled": { - "generatedAt": "2026-01-07T19:56:54.834Z", + "generatedAt": "2026-01-13T23:32:36.220Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/list-creatives-response.json b/dist/schemas/2.6.0/bundled/media-buy/list-creatives-response.json index ab7c867de7..8adabb227a 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/list-creatives-response.json +++ b/dist/schemas/2.6.0/bundled/media-buy/list-creatives-response.json @@ -1648,7 +1648,7 @@ } ], "_bundled": { - "generatedAt": "2026-01-07T19:56:54.835Z", + "generatedAt": "2026-01-13T23:32:36.221Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/package-request.json b/dist/schemas/2.6.0/bundled/media-buy/package-request.json index 7bc4ce1b75..a6cd805bcf 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/package-request.json +++ b/dist/schemas/2.6.0/bundled/media-buy/package-request.json @@ -92,6 +92,16 @@ "description": "Bid price for auction-based CPM pricing (required if using cpm-auction-option)", "minimum": 0 }, + "impressions": { + "type": "number", + "description": "Impression goal for this package", + "minimum": 0 + }, + "paused": { + "type": "boolean", + "description": "Whether this package should be created in a paused state. Paused packages do not deliver impressions. Defaults to false.", + "default": false + }, "targeting_overlay": { "title": "Targeting Overlay", "description": "Optional geographic refinements for media buys. Most targeting should be expressed in the brief and handled by the publisher. These fields are primarily for geographic restrictions (RCT testing, regulatory compliance).", @@ -1417,7 +1427,7 @@ ], "additionalProperties": true, "_bundled": { - "generatedAt": "2026-01-07T19:56:54.836Z", + "generatedAt": "2026-01-13T23:32:36.222Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/provide-performance-feedback-request.json b/dist/schemas/2.6.0/bundled/media-buy/provide-performance-feedback-request.json index 6a8d687c7f..1f528b1e8a 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/provide-performance-feedback-request.json +++ b/dist/schemas/2.6.0/bundled/media-buy/provide-performance-feedback-request.json @@ -110,7 +110,7 @@ ], "additionalProperties": true, "_bundled": { - "generatedAt": "2026-01-07T19:56:54.837Z", + "generatedAt": "2026-01-13T23:32:36.222Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/provide-performance-feedback-response.json b/dist/schemas/2.6.0/bundled/media-buy/provide-performance-feedback-response.json index 6b4878652f..a9865aef05 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/provide-performance-feedback-response.json +++ b/dist/schemas/2.6.0/bundled/media-buy/provide-performance-feedback-response.json @@ -111,7 +111,7 @@ } ], "_bundled": { - "generatedAt": "2026-01-07T19:56:54.837Z", + "generatedAt": "2026-01-13T23:32:36.223Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/sync-creatives-request.json b/dist/schemas/2.6.0/bundled/media-buy/sync-creatives-request.json index 0b56121358..da02739601 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/sync-creatives-request.json +++ b/dist/schemas/2.6.0/bundled/media-buy/sync-creatives-request.json @@ -1469,7 +1469,7 @@ } ], "_bundled": { - "generatedAt": "2026-01-07T19:56:54.839Z", + "generatedAt": "2026-01-13T23:32:36.224Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/sync-creatives-response.json b/dist/schemas/2.6.0/bundled/media-buy/sync-creatives-response.json index cab162ded4..3bb14a7129 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/sync-creatives-response.json +++ b/dist/schemas/2.6.0/bundled/media-buy/sync-creatives-response.json @@ -202,7 +202,7 @@ } ], "_bundled": { - "generatedAt": "2026-01-07T19:56:54.839Z", + "generatedAt": "2026-01-13T23:32:36.224Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/update-media-buy-request.json b/dist/schemas/2.6.0/bundled/media-buy/update-media-buy-request.json index c8d8fa805e..ce16186f4d 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/update-media-buy-request.json +++ b/dist/schemas/2.6.0/bundled/media-buy/update-media-buy-request.json @@ -77,6 +77,11 @@ "description": "Updated bid price for auction-based pricing options (only applies when pricing_option is auction-based)", "minimum": 0 }, + "impressions": { + "type": "number", + "description": "Updated impression goal for this package", + "minimum": 0 + }, "paused": { "type": "boolean", "description": "Pause/resume specific package (true = paused, false = active)" @@ -1519,7 +1524,7 @@ ], "additionalProperties": true, "_bundled": { - "generatedAt": "2026-01-07T19:56:54.840Z", + "generatedAt": "2026-01-13T23:32:36.225Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/media-buy/update-media-buy-response.json b/dist/schemas/2.6.0/bundled/media-buy/update-media-buy-response.json index 23ebd57c19..7828c98760 100644 --- a/dist/schemas/2.6.0/bundled/media-buy/update-media-buy-response.json +++ b/dist/schemas/2.6.0/bundled/media-buy/update-media-buy-response.json @@ -352,7 +352,7 @@ } ], "_bundled": { - "generatedAt": "2026-01-07T19:56:54.841Z", + "generatedAt": "2026-01-13T23:32:36.226Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/signals/activate-signal-request.json b/dist/schemas/2.6.0/bundled/signals/activate-signal-request.json index 24de122d6e..a2c0e35d27 100644 --- a/dist/schemas/2.6.0/bundled/signals/activate-signal-request.json +++ b/dist/schemas/2.6.0/bundled/signals/activate-signal-request.json @@ -84,7 +84,7 @@ ], "additionalProperties": true, "_bundled": { - "generatedAt": "2026-01-07T19:56:54.841Z", + "generatedAt": "2026-01-13T23:32:36.226Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/signals/activate-signal-response.json b/dist/schemas/2.6.0/bundled/signals/activate-signal-response.json index 6e532f84b2..15b22110fa 100644 --- a/dist/schemas/2.6.0/bundled/signals/activate-signal-response.json +++ b/dist/schemas/2.6.0/bundled/signals/activate-signal-response.json @@ -289,7 +289,7 @@ } ], "_bundled": { - "generatedAt": "2026-01-07T19:56:54.842Z", + "generatedAt": "2026-01-13T23:32:36.226Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/signals/get-signals-request.json b/dist/schemas/2.6.0/bundled/signals/get-signals-request.json index 85d7c3eb36..91146046e7 100644 --- a/dist/schemas/2.6.0/bundled/signals/get-signals-request.json +++ b/dist/schemas/2.6.0/bundled/signals/get-signals-request.json @@ -148,7 +148,7 @@ ], "additionalProperties": true, "_bundled": { - "generatedAt": "2026-01-07T19:56:54.842Z", + "generatedAt": "2026-01-13T23:32:36.227Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/bundled/signals/get-signals-response.json b/dist/schemas/2.6.0/bundled/signals/get-signals-response.json index d7acb6f13f..cbb4e048fe 100644 --- a/dist/schemas/2.6.0/bundled/signals/get-signals-response.json +++ b/dist/schemas/2.6.0/bundled/signals/get-signals-response.json @@ -321,7 +321,7 @@ ], "additionalProperties": true, "_bundled": { - "generatedAt": "2026-01-07T19:56:54.842Z", + "generatedAt": "2026-01-13T23:32:36.227Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/dist/schemas/2.6.0/core/identifier.json b/dist/schemas/2.6.0/core/identifier.json new file mode 100644 index 0000000000..46ef4de592 --- /dev/null +++ b/dist/schemas/2.6.0/core/identifier.json @@ -0,0 +1,19 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/2.6.0/core/identifier.json", + "title": "Identifier", + "description": "A property identifier with type and value. Used to identify properties across platforms (domains, app store IDs, etc.).", + "type": "object", + "properties": { + "type": { + "$ref": "/schemas/2.6.0/enums/identifier-types.json", + "description": "Type of identifier" + }, + "value": { + "type": "string", + "description": "The identifier value. For domain type: 'example.com' matches base domain plus www and m subdomains; 'edition.example.com' matches that specific subdomain; '*.example.com' matches ALL subdomains but NOT base domain" + } + }, + "required": ["type", "value"], + "additionalProperties": false +} diff --git a/dist/schemas/2.6.0/core/property-list-ref.json b/dist/schemas/2.6.0/core/property-list-ref.json new file mode 100644 index 0000000000..0d2ea81e99 --- /dev/null +++ b/dist/schemas/2.6.0/core/property-list-ref.json @@ -0,0 +1,25 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/2.6.0/core/property-list-ref.json", + "title": "Property List Reference", + "description": "Reference to an externally managed property list. Enables passing large property sets (50,000+) without embedding them in requests. The receiving agent fetches and caches the list independently.", + "type": "object", + "properties": { + "agent_url": { + "type": "string", + "format": "uri", + "description": "URL of the agent managing the property list" + }, + "list_id": { + "type": "string", + "description": "Identifier for the property list within the agent", + "minLength": 1 + }, + "auth_token": { + "type": "string", + "description": "JWT or other authorization token for accessing the list. Optional if the list is public or caller has implicit access." + } + }, + "required": ["agent_url", "list_id"], + "additionalProperties": false +} diff --git a/dist/schemas/2.6.0/creative/asset-types/index.json b/dist/schemas/2.6.0/creative/asset-types/index.json index 14a3531866..188def9e1c 100644 --- a/dist/schemas/2.6.0/creative/asset-types/index.json +++ b/dist/schemas/2.6.0/creative/asset-types/index.json @@ -4,7 +4,7 @@ "title": "AdCP Asset Type Registry", "description": "Registry of asset types used in AdCP creative manifests. Each asset type defines the structure of actual content payloads (what you send), not requirements or constraints (which belong in format specifications).", "version": "1.0.0", - "lastUpdated": "2026-01-07", + "lastUpdated": "2026-01-13", "asset_types": { "image": { "description": "Static image asset (JPG, PNG, GIF, WebP, SVG)", diff --git a/dist/schemas/2.6.0/enums/adcp-domain.json b/dist/schemas/2.6.0/enums/adcp-domain.json index 2d48f76e84..375666ca42 100644 --- a/dist/schemas/2.6.0/enums/adcp-domain.json +++ b/dist/schemas/2.6.0/enums/adcp-domain.json @@ -4,8 +4,11 @@ "title": "AdCP Domain", "description": "AdCP protocol domains for task categorization", "type": "string", - "enum": [ - "media-buy", - "signals" - ] + "enum": ["media-buy", "signals", "governance", "creative"], + "enumDescriptions": { + "media-buy": "Campaign creation, package management, and delivery optimization", + "signals": "Audience signal discovery and activation", + "governance": "Property governance (identity, authorization, data, selection), brand standards, and compliance", + "creative": "Creative asset management, format discovery, and rendering" + } } diff --git a/dist/schemas/2.6.0/enums/task-type.json b/dist/schemas/2.6.0/enums/task-type.json index 9dcf5a33b0..2690a3400a 100644 --- a/dist/schemas/2.6.0/enums/task-type.json +++ b/dist/schemas/2.6.0/enums/task-type.json @@ -9,18 +9,30 @@ "update_media_buy", "sync_creatives", "activate_signal", - "get_signals" + "get_signals", + "list_property_features", + "create_property_list", + "update_property_list", + "get_property_list", + "list_property_lists", + "delete_property_list" ], "enumDescriptions": { "create_media_buy": "Media-buy domain: Create a new advertising campaign with one or more packages", "update_media_buy": "Media-buy domain: Update campaign settings, package configuration, or delivery parameters", "sync_creatives": "Media-buy domain: Sync creative assets to publisher's library with upsert semantics", "activate_signal": "Signals domain: Activate an audience signal on a specific platform or account", - "get_signals": "Signals domain: Discover available audience signals based on natural language description" + "get_signals": "Signals domain: Discover available audience signals based on natural language description", + "list_property_features": "Property domain: Discover what features a governance agent can evaluate", + "create_property_list": "Property domain: Create a new property list with filters and brand manifest", + "update_property_list": "Property domain: Update an existing property list", + "get_property_list": "Property domain: Retrieve a property list with resolved properties", + "list_property_lists": "Property domain: List all accessible property lists", + "delete_property_list": "Property domain: Delete a property list" }, "notes": [ "Task types map to specific AdCP task operations", - "Each task type belongs to either the 'media-buy' or 'signals' domain", + "Each task type belongs to the 'media-buy', 'signals', 'property', or 'creative' domain", "This enum is used in task management APIs (tasks/list, tasks/get) and webhook payloads", "New task types require a minor version bump per semantic versioning" ] diff --git a/dist/schemas/2.6.0/extensions/extension-meta.json b/dist/schemas/2.6.0/extensions/extension-meta.json new file mode 100644 index 0000000000..3d86f6b51d --- /dev/null +++ b/dist/schemas/2.6.0/extensions/extension-meta.json @@ -0,0 +1,59 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/2.6.0/extensions/extension-meta.json", + "title": "AdCP Extension File Schema", + "description": "Schema that all extension files must follow. Combines metadata (valid_from, docs_url) with the actual extension data schema. Extensions are auto-discovered from /schemas/extensions/*.json and included in versioned builds based on valid_from/valid_until.", + "type": "object", + "properties": { + "$schema": { + "type": "string", + "const": "http://json-schema.org/draft-07/schema#" + }, + "$id": { + "type": "string", + "pattern": "^/schemas/extensions/[a-z][a-z0-9_]*\\.json$", + "description": "Extension ID following pattern /schemas/extensions/{namespace}.json" + }, + "title": { + "type": "string", + "description": "Human-readable title for the extension" + }, + "description": { + "type": "string", + "description": "Description of what this extension provides" + }, + "valid_from": { + "type": "string", + "pattern": "^\\d+\\.\\d+$", + "description": "Minimum AdCP version this extension is compatible with (e.g., '2.5'). Extension will be included in all versioned schema builds >= this version." + }, + "valid_until": { + "type": "string", + "pattern": "^\\d+\\.\\d+$", + "description": "Last AdCP version this extension is compatible with (e.g., '3.0'). Omit if extension is still valid for current and future versions." + }, + "docs_url": { + "type": "string", + "format": "uri", + "description": "URL to documentation for implementors of this extension" + }, + "type": { + "const": "object", + "description": "Extensions must be objects (data within ext.{namespace})" + }, + "properties": { + "type": "object", + "description": "Schema properties defining the structure of ext.{namespace} data", + "additionalProperties": true + }, + "required": { + "type": "array", + "items": { "type": "string" }, + "description": "Required properties within the extension data" + }, + "additionalProperties": { + "description": "Whether additional properties are allowed in the extension data" + } + }, + "required": ["$schema", "$id", "title", "description", "valid_from", "type", "properties"] +} diff --git a/dist/schemas/2.6.0/extensions/index.json b/dist/schemas/2.6.0/extensions/index.json new file mode 100644 index 0000000000..eae3746a98 --- /dev/null +++ b/dist/schemas/2.6.0/extensions/index.json @@ -0,0 +1,9 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/2.6.0/extensions/index.json", + "title": "AdCP Extension Registry", + "description": "Auto-generated registry of formal AdCP extensions. Extensions provide typed schemas for vendor-specific or domain-specific data within the ext field. Agents declare which extensions they support in their agent card.", + "_generated": true, + "_generatedAt": "2026-01-13T23:32:36.210Z", + "extensions": {} +} \ No newline at end of file diff --git a/dist/schemas/2.6.0/index.json b/dist/schemas/2.6.0/index.json index ecb888befd..ac15127520 100644 --- a/dist/schemas/2.6.0/index.json +++ b/dist/schemas/2.6.0/index.json @@ -31,7 +31,7 @@ ] } }, - "lastUpdated": "2026-01-07", + "lastUpdated": "2026-01-13", "baseUrl": "/schemas/2.6.0", "schemas": { "core": { @@ -168,6 +168,14 @@ "property-tag": { "$ref": "/schemas/2.6.0/core/property-tag.json", "description": "Tag for categorizing publisher properties - lowercase alphanumeric with underscores only" + }, + "property-list-ref": { + "$ref": "/schemas/2.6.0/core/property-list-ref.json", + "description": "Reference to an externally managed property list for passing large property sets" + }, + "identifier": { + "$ref": "/schemas/2.6.0/core/identifier.json", + "description": "A property identifier with type and value" } } }, @@ -220,7 +228,7 @@ }, "task-type": { "$ref": "/schemas/2.6.0/enums/task-type.json", - "description": "Valid AdCP task types across all domains (create_media_buy, update_media_buy, sync_creatives, activate_signal, get_signals)" + "description": "Valid AdCP task types across all domains (create_media_buy, update_media_buy, sync_creatives, activate_signal, get_signals, list_property_features, create_property_list, get_property_list, update_property_list, delete_property_list)" }, "asset-content-type": { "$ref": "/schemas/2.6.0/enums/asset-content-type.json", @@ -280,7 +288,7 @@ }, "adcp-domain": { "$ref": "/schemas/2.6.0/enums/adcp-domain.json", - "description": "AdCP protocol domains (media-buy, signals)" + "description": "AdCP protocol domains (media-buy, signals, governance)" }, "http-method": { "$ref": "/schemas/2.6.0/enums/http-method.json", @@ -562,6 +570,105 @@ } } }, + "governance": { + "description": "Governance protocol for property governance, brand standards, and compliance", + "supporting-schemas": { + "property-feature-definition": { + "$ref": "/schemas/2.6.0/property/property-feature-definition.json", + "description": "Definition of a feature that a governance agent can evaluate" + }, + "property-feature": { + "$ref": "/schemas/2.6.0/property/property-feature.json", + "description": "A discrete feature assessment for a property" + }, + "feature-requirement": { + "$ref": "/schemas/2.6.0/property/feature-requirement.json", + "description": "A feature-based requirement for property filtering" + }, + "property-error": { + "$ref": "/schemas/2.6.0/property/property-error.json", + "description": "Error information for a property that could not be evaluated" + }, + "property-list": { + "$ref": "/schemas/2.6.0/property/property-list.json", + "description": "A managed property list with optional filters for dynamic evaluation" + }, + "property-list-filters": { + "$ref": "/schemas/2.6.0/property/property-list-filters.json", + "description": "Filters that dynamically modify a property list when resolved" + }, + "property-list-changed-webhook": { + "$ref": "/schemas/2.6.0/property/property-list-changed-webhook.json", + "description": "Webhook payload when a property list changes" + }, + "base-property-source": { + "$ref": "/schemas/2.6.0/property/base-property-source.json", + "description": "A source of properties for a property list - supports publisher+tags, publisher+property_ids, or direct identifiers" + } + }, + "tasks": { + "list-property-features": { + "request": { + "$ref": "/schemas/2.6.0/property/list-property-features-request.json", + "description": "Request parameters for discovering governance agent capabilities" + }, + "response": { + "$ref": "/schemas/2.6.0/property/list-property-features-response.json", + "description": "Response payload for list_property_features task" + } + }, + "create-property-list": { + "request": { + "$ref": "/schemas/2.6.0/property/create-property-list-request.json", + "description": "Request parameters for creating a new property list" + }, + "response": { + "$ref": "/schemas/2.6.0/property/create-property-list-response.json", + "description": "Response payload for create_property_list task" + } + }, + "update-property-list": { + "request": { + "$ref": "/schemas/2.6.0/property/update-property-list-request.json", + "description": "Request parameters for updating an existing property list" + }, + "response": { + "$ref": "/schemas/2.6.0/property/update-property-list-response.json", + "description": "Response payload for update_property_list task" + } + }, + "get-property-list": { + "request": { + "$ref": "/schemas/2.6.0/property/get-property-list-request.json", + "description": "Request parameters for retrieving a property list with resolved properties" + }, + "response": { + "$ref": "/schemas/2.6.0/property/get-property-list-response.json", + "description": "Response payload for get_property_list task" + } + }, + "list-property-lists": { + "request": { + "$ref": "/schemas/2.6.0/property/list-property-lists-request.json", + "description": "Request parameters for listing property lists" + }, + "response": { + "$ref": "/schemas/2.6.0/property/list-property-lists-response.json", + "description": "Response payload for list_property_lists task" + } + }, + "delete-property-list": { + "request": { + "$ref": "/schemas/2.6.0/property/delete-property-list-request.json", + "description": "Request parameters for deleting a property list" + }, + "response": { + "$ref": "/schemas/2.6.0/property/delete-property-list-response.json", + "description": "Response payload for delete_property_list task" + } + } + } + }, "adagents": { "description": "Authorized sales agents file format specification", "$ref": "/schemas/2.6.0/adagents.json", @@ -573,9 +680,21 @@ "schemas": { "adcp-extension": { "$ref": "/schemas/2.6.0/protocols/adcp-extension.json", - "description": "AdCP extension for agent cards (MCP and A2A). Declares AdCP version and supported protocol domains." + "description": "AdCP extension for agent cards (MCP and A2A). Declares AdCP version, supported protocol domains, and typed extensions." } } + }, + "extensions": { + "description": "Typed extension schemas for vendor-specific or domain-specific data. Extensions define the structure of data within the ext.{namespace} field. Agents declare which extensions they support in their agent card.", + "registry": { + "$ref": "/schemas/2.6.0/extensions/index.json", + "description": "Auto-generated registry of all available extensions with metadata" + }, + "meta": { + "$ref": "/schemas/2.6.0/extensions/extension-meta.json", + "description": "Schema that all extension files must follow. Defines valid_from, valid_until, and extension data structure." + }, + "schemas": {} } }, "usage": { diff --git a/dist/schemas/2.6.0/media-buy/get-products-request.json b/dist/schemas/2.6.0/media-buy/get-products-request.json index b44dfabdbe..deab15d64c 100644 --- a/dist/schemas/2.6.0/media-buy/get-products-request.json +++ b/dist/schemas/2.6.0/media-buy/get-products-request.json @@ -16,6 +16,10 @@ "filters": { "$ref": "/schemas/2.6.0/core/product-filters.json" }, + "property_list": { + "$ref": "/schemas/2.6.0/core/property-list-ref.json", + "description": "[AdCP 3.0] Reference to an externally managed property list. When provided, the sales agent should filter products to only those available on properties in the list." + }, "context": { "$ref": "/schemas/2.6.0/core/context.json" }, diff --git a/dist/schemas/2.6.0/media-buy/get-products-response.json b/dist/schemas/2.6.0/media-buy/get-products-response.json index 7212c9b4db..ae3c07fcaf 100644 --- a/dist/schemas/2.6.0/media-buy/get-products-response.json +++ b/dist/schemas/2.6.0/media-buy/get-products-response.json @@ -19,6 +19,10 @@ "$ref": "/schemas/2.6.0/core/error.json" } }, + "property_list_applied": { + "type": "boolean", + "description": "[AdCP 3.0] Indicates whether property_list filtering was applied. True if the agent filtered products based on the provided property_list. Absent or false if property_list was not provided or not supported by this agent." + }, "context": { "$ref": "/schemas/2.6.0/core/context.json" }, diff --git a/dist/schemas/2.6.0/media-buy/package-request.json b/dist/schemas/2.6.0/media-buy/package-request.json index 785ccc02f9..fc2fb88841 100644 --- a/dist/schemas/2.6.0/media-buy/package-request.json +++ b/dist/schemas/2.6.0/media-buy/package-request.json @@ -38,6 +38,16 @@ "description": "Bid price for auction-based CPM pricing (required if using cpm-auction-option)", "minimum": 0 }, + "impressions": { + "type": "number", + "description": "Impression goal for this package", + "minimum": 0 + }, + "paused": { + "type": "boolean", + "description": "Whether this package should be created in a paused state. Paused packages do not deliver impressions. Defaults to false.", + "default": false + }, "targeting_overlay": { "$ref": "/schemas/2.6.0/core/targeting.json" }, diff --git a/dist/schemas/2.6.0/media-buy/update-media-buy-request.json b/dist/schemas/2.6.0/media-buy/update-media-buy-request.json index 40033c5589..f1d9d3e6db 100644 --- a/dist/schemas/2.6.0/media-buy/update-media-buy-request.json +++ b/dist/schemas/2.6.0/media-buy/update-media-buy-request.json @@ -52,6 +52,11 @@ "description": "Updated bid price for auction-based pricing options (only applies when pricing_option is auction-based)", "minimum": 0 }, + "impressions": { + "type": "number", + "description": "Updated impression goal for this package", + "minimum": 0 + }, "paused": { "type": "boolean", "description": "Pause/resume specific package (true = paused, false = active)" diff --git a/dist/schemas/2.6.0/property/authorization-result.json b/dist/schemas/2.6.0/property/authorization-result.json new file mode 100644 index 0000000000..e43b55cee8 --- /dev/null +++ b/dist/schemas/2.6.0/property/authorization-result.json @@ -0,0 +1,41 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/2.6.0/property/authorization-result.json", + "title": "Authorization Result", + "description": "Result of validating sales agent authorization for a property. Checks if the sales agent is listed in the property's adagents.json.", + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": ["authorized", "unauthorized", "unknown"], + "description": "Authorization status: authorized (agent in adagents.json), unauthorized (agent not in adagents.json), unknown (could not fetch or parse adagents.json)" + }, + "publisher_domain": { + "type": "string", + "description": "The publisher domain where adagents.json was checked" + }, + "sales_agent_url": { + "type": "string", + "format": "uri", + "description": "The sales agent URL that was validated" + }, + "violation": { + "type": "object", + "description": "Details about the authorization failure (only present for unauthorized status)", + "properties": { + "code": { + "type": "string", + "description": "Machine-readable violation code" + }, + "message": { + "type": "string", + "description": "Human-readable violation description" + } + }, + "required": ["code", "message"], + "additionalProperties": false + } + }, + "required": ["status"], + "additionalProperties": false +} diff --git a/dist/schemas/2.6.0/property/base-property-source.json b/dist/schemas/2.6.0/property/base-property-source.json new file mode 100644 index 0000000000..107ab2048e --- /dev/null +++ b/dist/schemas/2.6.0/property/base-property-source.json @@ -0,0 +1,87 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/2.6.0/property/base-property-source.json", + "title": "Base Property Source", + "description": "A source of properties for a property list. Supports three selection patterns: publisher with tags, publisher with property IDs, or direct identifiers.", + "discriminator": { + "propertyName": "selection_type" + }, + "oneOf": [ + { + "type": "object", + "title": "Publisher Tags Source", + "description": "Select properties from a publisher by tag membership", + "properties": { + "selection_type": { + "type": "string", + "const": "publisher_tags", + "description": "Discriminator indicating selection by property tags within a publisher" + }, + "publisher_domain": { + "type": "string", + "description": "Domain where publisher's adagents.json is hosted (e.g., 'raptive.com')", + "pattern": "^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$" + }, + "tags": { + "type": "array", + "description": "Property tags from the publisher's adagents.json. Selects all properties with these tags.", + "items": { + "$ref": "/schemas/2.6.0/core/property-tag.json" + }, + "minItems": 1 + } + }, + "required": ["selection_type", "publisher_domain", "tags"], + "additionalProperties": false + }, + { + "type": "object", + "title": "Publisher Property IDs Source", + "description": "Select specific properties from a publisher by ID", + "properties": { + "selection_type": { + "type": "string", + "const": "publisher_ids", + "description": "Discriminator indicating selection by specific property IDs within a publisher" + }, + "publisher_domain": { + "type": "string", + "description": "Domain where publisher's adagents.json is hosted (e.g., 'raptive.com')", + "pattern": "^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$" + }, + "property_ids": { + "type": "array", + "description": "Specific property IDs from the publisher's adagents.json", + "items": { + "$ref": "/schemas/2.6.0/core/property-id.json" + }, + "minItems": 1 + } + }, + "required": ["selection_type", "publisher_domain", "property_ids"], + "additionalProperties": false + }, + { + "type": "object", + "title": "Direct Identifiers Source", + "description": "Select properties by direct identifiers (domains, app IDs, etc.) without publisher context", + "properties": { + "selection_type": { + "type": "string", + "const": "identifiers", + "description": "Discriminator indicating selection by direct identifiers" + }, + "identifiers": { + "type": "array", + "description": "Direct property identifiers (domains, app IDs, etc.)", + "items": { + "$ref": "/schemas/2.6.0/core/identifier.json" + }, + "minItems": 1 + } + }, + "required": ["selection_type", "identifiers"], + "additionalProperties": false + } + ] +} diff --git a/dist/schemas/2.6.0/property/create-property-list-request.json b/dist/schemas/2.6.0/property/create-property-list-request.json new file mode 100644 index 0000000000..1391c41730 --- /dev/null +++ b/dist/schemas/2.6.0/property/create-property-list-request.json @@ -0,0 +1,40 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/2.6.0/property/create-property-list-request.json", + "title": "Create Property List Request", + "description": "Request parameters for creating a new property list", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Human-readable name for the list" + }, + "description": { + "type": "string", + "description": "Description of the list's purpose" + }, + "base_properties": { + "type": "array", + "description": "Array of property sources to evaluate. Each entry is a discriminated union: publisher_tags (publisher_domain + tags), publisher_ids (publisher_domain + property_ids), or identifiers (direct identifiers). If omitted, queries the agent's entire property database.", + "items": { + "$ref": "/schemas/2.6.0/property/base-property-source.json" + } + }, + "filters": { + "$ref": "/schemas/2.6.0/property/property-list-filters.json", + "description": "Dynamic filters to apply when resolving the list" + }, + "brand_manifest": { + "$ref": "/schemas/2.6.0/core/brand-manifest.json", + "description": "Brand identity and requirements. When provided, the agent automatically applies appropriate rules based on brand characteristics (industry, target_audience, etc.)." + }, + "context": { + "$ref": "/schemas/2.6.0/core/context.json" + }, + "ext": { + "$ref": "/schemas/2.6.0/core/ext.json" + } + }, + "required": ["name"], + "additionalProperties": false +} diff --git a/dist/schemas/2.6.0/property/create-property-list-response.json b/dist/schemas/2.6.0/property/create-property-list-response.json new file mode 100644 index 0000000000..d745d41653 --- /dev/null +++ b/dist/schemas/2.6.0/property/create-property-list-response.json @@ -0,0 +1,22 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/2.6.0/property/create-property-list-response.json", + "title": "Create Property List Response", + "description": "Response payload for create_property_list task", + "type": "object", + "properties": { + "list": { + "$ref": "/schemas/2.6.0/property/property-list.json", + "description": "The created property list" + }, + "auth_token": { + "type": "string", + "description": "Token that can be shared with sellers to authorize fetching this list. Store this - it is only returned at creation time." + }, + "ext": { + "$ref": "/schemas/2.6.0/core/ext.json" + } + }, + "required": ["list", "auth_token"], + "additionalProperties": false +} diff --git a/dist/schemas/2.6.0/property/delete-property-list-request.json b/dist/schemas/2.6.0/property/delete-property-list-request.json new file mode 100644 index 0000000000..f0b9bf2b7c --- /dev/null +++ b/dist/schemas/2.6.0/property/delete-property-list-request.json @@ -0,0 +1,21 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/2.6.0/property/delete-property-list-request.json", + "title": "Delete Property List Request", + "description": "Request parameters for deleting a property list", + "type": "object", + "properties": { + "list_id": { + "type": "string", + "description": "ID of the property list to delete" + }, + "context": { + "$ref": "/schemas/2.6.0/core/context.json" + }, + "ext": { + "$ref": "/schemas/2.6.0/core/ext.json" + } + }, + "required": ["list_id"], + "additionalProperties": false +} diff --git a/dist/schemas/2.6.0/property/delete-property-list-response.json b/dist/schemas/2.6.0/property/delete-property-list-response.json new file mode 100644 index 0000000000..548b2383c1 --- /dev/null +++ b/dist/schemas/2.6.0/property/delete-property-list-response.json @@ -0,0 +1,22 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/2.6.0/property/delete-property-list-response.json", + "title": "Delete Property List Response", + "description": "Response payload for delete_property_list task", + "type": "object", + "properties": { + "deleted": { + "type": "boolean", + "description": "Whether the list was successfully deleted" + }, + "list_id": { + "type": "string", + "description": "ID of the deleted list" + }, + "ext": { + "$ref": "/schemas/2.6.0/core/ext.json" + } + }, + "required": ["deleted", "list_id"], + "additionalProperties": false +} diff --git a/dist/schemas/2.6.0/property/delivery-record.json b/dist/schemas/2.6.0/property/delivery-record.json new file mode 100644 index 0000000000..dcc200dcc2 --- /dev/null +++ b/dist/schemas/2.6.0/property/delivery-record.json @@ -0,0 +1,32 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/2.6.0/property/delivery-record.json", + "title": "Delivery Record", + "description": "A single delivery record representing impressions served to a property identifier. Used as input to validate_property_delivery.", + "type": "object", + "properties": { + "identifier": { + "$ref": "/schemas/2.6.0/core/identifier.json", + "description": "The property identifier where impressions were delivered" + }, + "impressions": { + "type": "integer", + "minimum": 0, + "description": "Number of impressions delivered to this identifier" + }, + "record_id": { + "type": "string", + "description": "Optional client-provided ID for correlating results back to source data" + }, + "sales_agent_url": { + "type": "string", + "format": "uri", + "description": "URL of the sales agent that sold this inventory. If provided, authorization is validated against the property's adagents.json." + }, + "ext": { + "$ref": "/schemas/2.6.0/core/ext.json" + } + }, + "required": ["identifier", "impressions"], + "additionalProperties": false +} diff --git a/dist/schemas/2.6.0/property/feature-requirement.json b/dist/schemas/2.6.0/property/feature-requirement.json new file mode 100644 index 0000000000..87ffb718ec --- /dev/null +++ b/dist/schemas/2.6.0/property/feature-requirement.json @@ -0,0 +1,34 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/2.6.0/property/feature-requirement.json", + "title": "Feature Requirement", + "description": "A feature-based requirement for property filtering. Use min_value/max_value for quantitative features, allowed_values for binary/categorical features.", + "type": "object", + "properties": { + "feature_id": { + "type": "string", + "description": "Feature to evaluate (discovered via list_property_features)" + }, + "min_value": { + "type": "number", + "description": "Minimum numeric value required (for quantitative features)" + }, + "max_value": { + "type": "number", + "description": "Maximum numeric value allowed (for quantitative features)" + }, + "allowed_values": { + "type": "array", + "description": "Values that pass the requirement (for binary/categorical features)", + "items": {} + }, + "if_not_covered": { + "type": "string", + "enum": ["exclude", "include"], + "default": "exclude", + "description": "How to handle properties where this feature is not covered. 'exclude' (default): property is removed from the list. 'include': property passes this requirement (fail-open)." + } + }, + "required": ["feature_id"], + "additionalProperties": false +} diff --git a/dist/schemas/2.6.0/property/get-property-features-request.json b/dist/schemas/2.6.0/property/get-property-features-request.json new file mode 100644 index 0000000000..b74b43887a --- /dev/null +++ b/dist/schemas/2.6.0/property/get-property-features-request.json @@ -0,0 +1,68 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/2.6.0/property/get-property-features-request.json", + "title": "Get Property Features Request", + "description": "Request payload for get_property_features task. Retrieves feature values for properties from a governance agent. Supports two modes: explicit property list OR publisher-based discovery.", + "type": "object", + "properties": { + "properties": { + "type": "array", + "description": "Explicit list of properties to get features for. Can be domain strings or structured property references. Use this when you know exactly which properties you want.", + "items": { + "oneOf": [ + { + "type": "string", + "description": "Domain string (e.g., 'example.com')" + }, + { + "$ref": "/schemas/2.6.0/core/property-id.json" + } + ] + }, + "minItems": 1, + "maxItems": 100 + }, + "publisher_domain": { + "type": "string", + "description": "Publisher domain to discover properties for. Use this to get features for all properties belonging to a publisher. Can be combined with property_types and property_tags for filtering." + }, + "property_types": { + "type": "array", + "description": "Filter to specific property types (e.g., 'website', 'mobile_app', 'ctv_app'). Only applies when using publisher_domain.", + "items": { + "$ref": "/schemas/2.6.0/enums/property-type.json" + } + }, + "property_tags": { + "type": "array", + "description": "Filter to properties with these tags. Only applies when using publisher_domain.", + "items": { + "$ref": "/schemas/2.6.0/core/property-tag.json" + } + }, + "feature_ids": { + "type": "array", + "description": "Optional filter to specific features. If omitted, returns all available features.", + "items": { + "type": "string" + } + }, + "context": { + "$ref": "/schemas/2.6.0/core/context.json" + }, + "ext": { + "$ref": "/schemas/2.6.0/core/ext.json" + } + }, + "oneOf": [ + { + "required": ["properties"], + "description": "Explicit property list mode" + }, + { + "required": ["publisher_domain"], + "description": "Publisher discovery mode" + } + ], + "additionalProperties": false +} diff --git a/dist/schemas/2.6.0/property/get-property-features-response.json b/dist/schemas/2.6.0/property/get-property-features-response.json new file mode 100644 index 0000000000..56b2334b29 --- /dev/null +++ b/dist/schemas/2.6.0/property/get-property-features-response.json @@ -0,0 +1,28 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/2.6.0/property/get-property-features-response.json", + "title": "Get Property Features Response", + "description": "Response payload for get_property_features task. Returns feature values for requested properties.", + "type": "object", + "properties": { + "results": { + "type": "array", + "description": "Feature values for each requested property", + "items": { + "$ref": "/schemas/2.6.0/property/property-feature-result.json" + } + }, + "errors": { + "type": "array", + "description": "Errors for properties that could not be processed", + "items": { + "$ref": "/schemas/2.6.0/core/error.json" + } + }, + "ext": { + "$ref": "/schemas/2.6.0/core/ext.json" + } + }, + "required": ["results"], + "additionalProperties": false +} diff --git a/dist/schemas/2.6.0/property/get-property-list-request.json b/dist/schemas/2.6.0/property/get-property-list-request.json new file mode 100644 index 0000000000..eb7d75488e --- /dev/null +++ b/dist/schemas/2.6.0/property/get-property-list-request.json @@ -0,0 +1,35 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/2.6.0/property/get-property-list-request.json", + "title": "Get Property List Request", + "description": "Request parameters for retrieving a property list with resolved identifiers", + "type": "object", + "properties": { + "list_id": { + "type": "string", + "description": "ID of the property list to retrieve" + }, + "resolve": { + "type": "boolean", + "description": "Whether to apply filters and return resolved identifiers (default: true)", + "default": true + }, + "max_results": { + "type": "integer", + "description": "Maximum identifiers to return (for large lists)", + "minimum": 1 + }, + "cursor": { + "type": "string", + "description": "Pagination cursor for large result sets" + }, + "context": { + "$ref": "/schemas/2.6.0/core/context.json" + }, + "ext": { + "$ref": "/schemas/2.6.0/core/ext.json" + } + }, + "required": ["list_id"], + "additionalProperties": false +} diff --git a/dist/schemas/2.6.0/property/get-property-list-response.json b/dist/schemas/2.6.0/property/get-property-list-response.json new file mode 100644 index 0000000000..a4113455ac --- /dev/null +++ b/dist/schemas/2.6.0/property/get-property-list-response.json @@ -0,0 +1,68 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/2.6.0/property/get-property-list-response.json", + "title": "Get Property List Response", + "description": "Response payload for get_property_list task. Returns identifiers only (not full property objects or scores). Consumers should cache the resolved identifiers and refresh based on cache_valid_until.", + "type": "object", + "properties": { + "list": { + "$ref": "/schemas/2.6.0/property/property-list.json", + "description": "The property list metadata (always returned)" + }, + "identifiers": { + "type": "array", + "description": "Resolved identifiers that passed filters (if resolve=true). Cache these locally for real-time use.", + "items": { + "$ref": "/schemas/2.6.0/core/identifier.json" + } + }, + "total_count": { + "type": "integer", + "description": "Total number of identifiers in resolved list" + }, + "returned_count": { + "type": "integer", + "description": "Number of identifiers returned in this response" + }, + "pagination": { + "type": "object", + "description": "Pagination information", + "properties": { + "has_more": { + "type": "boolean", + "description": "Whether more results are available" + }, + "cursor": { + "type": "string", + "description": "Cursor for next page" + } + }, + "additionalProperties": false + }, + "resolved_at": { + "type": "string", + "format": "date-time", + "description": "When the list was resolved" + }, + "cache_valid_until": { + "type": "string", + "format": "date-time", + "description": "Cache expiration timestamp. Re-fetch the list after this time to get updated identifiers." + }, + "coverage_gaps": { + "type": "object", + "description": "Properties included in the list despite missing feature data. Only present when a feature_requirement has if_not_covered='include'. Maps feature_id to list of identifiers not covered for that feature.", + "additionalProperties": { + "type": "array", + "items": { + "$ref": "/schemas/2.6.0/core/identifier.json" + } + } + }, + "ext": { + "$ref": "/schemas/2.6.0/core/ext.json" + } + }, + "required": ["list"], + "additionalProperties": false +} diff --git a/dist/schemas/2.6.0/property/list-property-features-request.json b/dist/schemas/2.6.0/property/list-property-features-request.json new file mode 100644 index 0000000000..5beb1ded0d --- /dev/null +++ b/dist/schemas/2.6.0/property/list-property-features-request.json @@ -0,0 +1,27 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/2.6.0/property/list-property-features-request.json", + "title": "List Property Features Request", + "description": "Request payload for list_property_features task. Discovers what features a governance agent can evaluate.", + "type": "object", + "properties": { + "property_types": { + "type": "array", + "description": "Filter to features available for these property types", + "items": { + "type": "string" + } + }, + "countries": { + "type": "array", + "description": "Filter to features available in these countries", + "items": { + "type": "string" + } + }, + "ext": { + "$ref": "/schemas/2.6.0/core/ext.json" + } + }, + "additionalProperties": false +} diff --git a/dist/schemas/2.6.0/property/list-property-features-response.json b/dist/schemas/2.6.0/property/list-property-features-response.json new file mode 100644 index 0000000000..9be8c83bbe --- /dev/null +++ b/dist/schemas/2.6.0/property/list-property-features-response.json @@ -0,0 +1,21 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/2.6.0/property/list-property-features-response.json", + "title": "List Property Features Response", + "description": "Response payload for list_property_features task. Returns the features this governance agent can evaluate.", + "type": "object", + "properties": { + "features": { + "type": "array", + "description": "Features this agent can evaluate", + "items": { + "$ref": "/schemas/2.6.0/property/property-feature-definition.json" + } + }, + "ext": { + "$ref": "/schemas/2.6.0/core/ext.json" + } + }, + "required": ["features"], + "additionalProperties": false +} diff --git a/dist/schemas/2.6.0/property/list-property-lists-request.json b/dist/schemas/2.6.0/property/list-property-lists-request.json new file mode 100644 index 0000000000..f7b860aa14 --- /dev/null +++ b/dist/schemas/2.6.0/property/list-property-lists-request.json @@ -0,0 +1,34 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/2.6.0/property/list-property-lists-request.json", + "title": "List Property Lists Request", + "description": "Request parameters for listing property lists", + "type": "object", + "properties": { + "principal": { + "type": "string", + "description": "Filter to lists owned by this principal" + }, + "name_contains": { + "type": "string", + "description": "Filter to lists whose name contains this string" + }, + "max_results": { + "type": "integer", + "description": "Maximum lists to return", + "minimum": 1, + "default": 100 + }, + "cursor": { + "type": "string", + "description": "Pagination cursor" + }, + "context": { + "$ref": "/schemas/2.6.0/core/context.json" + }, + "ext": { + "$ref": "/schemas/2.6.0/core/ext.json" + } + }, + "additionalProperties": false +} diff --git a/dist/schemas/2.6.0/property/list-property-lists-response.json b/dist/schemas/2.6.0/property/list-property-lists-response.json new file mode 100644 index 0000000000..cf3b8e95c7 --- /dev/null +++ b/dist/schemas/2.6.0/property/list-property-lists-response.json @@ -0,0 +1,44 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/2.6.0/property/list-property-lists-response.json", + "title": "List Property Lists Response", + "description": "Response payload for list_property_lists task", + "type": "object", + "properties": { + "lists": { + "type": "array", + "description": "Array of property lists (metadata only, not resolved properties)", + "items": { + "$ref": "/schemas/2.6.0/property/property-list.json" + } + }, + "total_count": { + "type": "integer", + "description": "Total number of lists matching criteria" + }, + "returned_count": { + "type": "integer", + "description": "Number of lists returned in this response" + }, + "pagination": { + "type": "object", + "description": "Pagination information", + "properties": { + "has_more": { + "type": "boolean", + "description": "Whether more results are available" + }, + "cursor": { + "type": "string", + "description": "Cursor for next page" + } + }, + "additionalProperties": false + }, + "ext": { + "$ref": "/schemas/2.6.0/core/ext.json" + } + }, + "required": ["lists"], + "additionalProperties": false +} diff --git a/dist/schemas/2.6.0/property/property-error.json b/dist/schemas/2.6.0/property/property-error.json new file mode 100644 index 0000000000..e05248cf47 --- /dev/null +++ b/dist/schemas/2.6.0/property/property-error.json @@ -0,0 +1,31 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/2.6.0/property/property-error.json", + "title": "Property Error", + "description": "Error information for a property that could not be evaluated", + "type": "object", + "properties": { + "code": { + "type": "string", + "description": "Error code", + "enum": [ + "PROPERTY_NOT_FOUND", + "PROPERTY_NOT_MONITORED", + "LIST_NOT_FOUND", + "LIST_ACCESS_DENIED", + "METHODOLOGY_NOT_SUPPORTED", + "JURISDICTION_NOT_SUPPORTED" + ] + }, + "property": { + "$ref": "/schemas/2.6.0/core/property.json", + "description": "The property that caused the error" + }, + "message": { + "type": "string", + "description": "Human-readable error message" + } + }, + "required": ["code", "message"], + "additionalProperties": false +} diff --git a/dist/schemas/2.6.0/property/property-feature-definition.json b/dist/schemas/2.6.0/property/property-feature-definition.json new file mode 100644 index 0000000000..5c9adcac77 --- /dev/null +++ b/dist/schemas/2.6.0/property/property-feature-definition.json @@ -0,0 +1,84 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/2.6.0/property/property-feature-definition.json", + "title": "Property Feature Definition", + "description": "Defines a feature that a governance agent can evaluate for properties. Used in list_property_features to advertise agent capabilities.", + "type": "object", + "properties": { + "feature_id": { + "type": "string", + "description": "Unique identifier for this feature (e.g., 'consent_quality', 'carbon_score', 'coppa_certified')" + }, + "name": { + "type": "string", + "description": "Human-readable name for the feature" + }, + "description": { + "type": "string", + "description": "Description of what this feature measures or represents" + }, + "type": { + "type": "string", + "enum": ["binary", "quantitative", "categorical"], + "description": "The type of values this feature produces: binary (true/false), quantitative (numeric range), categorical (enumerated values)" + }, + "range": { + "type": "object", + "description": "For quantitative features, the valid range of values", + "properties": { + "min": { + "type": "number", + "description": "Minimum value" + }, + "max": { + "type": "number", + "description": "Maximum value" + } + }, + "required": ["min", "max"], + "additionalProperties": false + }, + "allowed_values": { + "type": "array", + "description": "For categorical features, the set of valid values", + "items": { + "type": "string" + } + }, + "coverage": { + "type": "object", + "description": "What this feature covers (empty arrays = all)", + "properties": { + "property_types": { + "type": "array", + "description": "Property types this feature applies to", + "items": { + "type": "string" + } + }, + "countries": { + "type": "array", + "description": "Countries where this feature is available", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + }, + "methodology_url": { + "type": "string", + "format": "uri", + "description": "URL to documentation explaining how this feature is calculated/measured" + }, + "methodology_version": { + "type": "string", + "description": "Version identifier for the methodology (for audit trails)" + }, + "ext": { + "$ref": "/schemas/2.6.0/core/ext.json" + } + }, + "required": ["feature_id", "name", "type", "methodology_url"], + "additionalProperties": false +} diff --git a/dist/schemas/2.6.0/property/property-feature-result.json b/dist/schemas/2.6.0/property/property-feature-result.json new file mode 100644 index 0000000000..74fa6bfad5 --- /dev/null +++ b/dist/schemas/2.6.0/property/property-feature-result.json @@ -0,0 +1,43 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/2.6.0/property/property-feature-result.json", + "title": "Property Feature Result", + "description": "Feature values for a single property from a governance agent.", + "type": "object", + "properties": { + "property": { + "oneOf": [ + { + "type": "string", + "description": "Domain string (e.g., 'example.com')" + }, + { + "$ref": "/schemas/2.6.0/core/property-id.json" + } + ], + "description": "The property these features apply to" + }, + "features": { + "type": "object", + "description": "Map of feature_id to feature value", + "additionalProperties": { + "$ref": "/schemas/2.6.0/property/property-feature-value.json" + } + }, + "coverage_status": { + "type": "string", + "enum": ["covered", "not_covered", "pending"], + "description": "Whether this property is covered by this governance agent: covered (has data), not_covered (not measured), pending (measurement in progress)" + }, + "last_evaluated": { + "type": "string", + "format": "date-time", + "description": "When features were last evaluated for this property" + }, + "ext": { + "$ref": "/schemas/2.6.0/core/ext.json" + } + }, + "required": ["property", "coverage_status"], + "additionalProperties": false +} diff --git a/dist/schemas/2.6.0/property/property-feature-value.json b/dist/schemas/2.6.0/property/property-feature-value.json new file mode 100644 index 0000000000..aad2b0083f --- /dev/null +++ b/dist/schemas/2.6.0/property/property-feature-value.json @@ -0,0 +1,51 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/2.6.0/property/property-feature-value.json", + "title": "Property Feature Value", + "description": "A single feature value for a property. Structure varies by feature type (binary, quantitative, categorical).", + "type": "object", + "properties": { + "value": { + "description": "The feature value. Type depends on feature definition: boolean for binary, number for quantitative, string for categorical.", + "oneOf": [ + { "type": "boolean" }, + { "type": "number" }, + { "type": "string" } + ] + }, + "unit": { + "type": "string", + "description": "Unit of measurement for quantitative values (e.g., 'gCO2e/1000_impressions', 'percentage')" + }, + "confidence": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "Confidence score for this value (0-1)" + }, + "measured_at": { + "type": "string", + "format": "date-time", + "description": "When this specific value was measured" + }, + "expires_at": { + "type": "string", + "format": "date-time", + "description": "When this certification/value expires (for time-limited certifications)" + }, + "methodology_version": { + "type": "string", + "description": "Version of the methodology used to calculate this value" + }, + "details": { + "type": "object", + "description": "Additional vendor-specific details about this measurement", + "additionalProperties": true + }, + "ext": { + "$ref": "/schemas/2.6.0/core/ext.json" + } + }, + "required": ["value"], + "additionalProperties": false +} diff --git a/dist/schemas/2.6.0/property/property-feature.json b/dist/schemas/2.6.0/property/property-feature.json new file mode 100644 index 0000000000..81735ad433 --- /dev/null +++ b/dist/schemas/2.6.0/property/property-feature.json @@ -0,0 +1,23 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/2.6.0/property/property-feature.json", + "title": "Property Feature", + "description": "A discrete feature assessment for a property (e.g., from app store privacy labels)", + "type": "object", + "properties": { + "feature_id": { + "type": "string", + "description": "Identifier for the feature being assessed" + }, + "value": { + "type": "string", + "description": "The feature value" + }, + "source": { + "type": "string", + "description": "Source of the feature data (e.g., app_store_privacy_label, tcf_string)" + } + }, + "required": ["feature_id", "value"], + "additionalProperties": false +} diff --git a/dist/schemas/2.6.0/property/property-list-changed-webhook.json b/dist/schemas/2.6.0/property/property-list-changed-webhook.json new file mode 100644 index 0000000000..c1ce36f68a --- /dev/null +++ b/dist/schemas/2.6.0/property/property-list-changed-webhook.json @@ -0,0 +1,60 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/2.6.0/property/property-list-changed-webhook.json", + "title": "Property List Changed Webhook", + "description": "Webhook notification sent when a property list's resolved properties change. Contains a summary only - recipients must call get_property_list to retrieve the updated properties. This keeps payloads small and avoids redundant data transfer.", + "type": "object", + "properties": { + "event": { + "type": "string", + "const": "property_list_changed", + "description": "The event type" + }, + "list_id": { + "type": "string", + "description": "ID of the property list that changed" + }, + "list_name": { + "type": "string", + "description": "Name of the property list" + }, + "change_summary": { + "type": "object", + "description": "Summary of changes to the resolved list", + "properties": { + "properties_added": { + "type": "integer", + "description": "Number of properties added since last resolution" + }, + "properties_removed": { + "type": "integer", + "description": "Number of properties removed since last resolution" + }, + "total_properties": { + "type": "integer", + "description": "Total properties in the resolved list" + } + }, + "additionalProperties": false + }, + "resolved_at": { + "type": "string", + "format": "date-time", + "description": "When the list was re-resolved" + }, + "cache_valid_until": { + "type": "string", + "format": "date-time", + "description": "When the consumer should refresh from the governance agent" + }, + "signature": { + "type": "string", + "description": "Cryptographic signature of the webhook payload, signed with the agent's private key. Recipients MUST verify this signature." + }, + "ext": { + "$ref": "/schemas/2.6.0/core/ext.json" + } + }, + "required": ["event", "list_id", "resolved_at", "signature"], + "additionalProperties": false +} diff --git a/dist/schemas/2.6.0/property/property-list-filters.json b/dist/schemas/2.6.0/property/property-list-filters.json new file mode 100644 index 0000000000..e8968dcef1 --- /dev/null +++ b/dist/schemas/2.6.0/property/property-list-filters.json @@ -0,0 +1,47 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/2.6.0/property/property-list-filters.json", + "title": "Property List Filters", + "description": "Filters that dynamically modify a property list when resolved", + "type": "object", + "properties": { + "countries_all": { + "type": "array", + "description": "Property must have feature data for ALL listed countries (ISO codes). Required.", + "items": { + "type": "string", + "pattern": "^[A-Z]{2}$" + } + }, + "channels_any": { + "type": "array", + "description": "Property must support ANY of the listed channels. Required.", + "items": { + "$ref": "/schemas/2.6.0/enums/channels.json" + } + }, + "property_types": { + "type": "array", + "description": "Filter to these property types", + "items": { + "$ref": "/schemas/2.6.0/enums/property-type.json" + } + }, + "feature_requirements": { + "type": "array", + "description": "Feature-based requirements. Property must pass ALL requirements (AND logic).", + "items": { + "$ref": "/schemas/2.6.0/property/feature-requirement.json" + } + }, + "exclude_identifiers": { + "type": "array", + "description": "Identifiers to always exclude from results", + "items": { + "$ref": "/schemas/2.6.0/core/identifier.json" + } + } + }, + "required": ["countries_all", "channels_any"], + "additionalProperties": false +} diff --git a/dist/schemas/2.6.0/property/property-list.json b/dist/schemas/2.6.0/property/property-list.json new file mode 100644 index 0000000000..647670c5cc --- /dev/null +++ b/dist/schemas/2.6.0/property/property-list.json @@ -0,0 +1,67 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/2.6.0/property/property-list.json", + "title": "Property List", + "description": "A managed property list with optional filters for dynamic evaluation. Lists are resolved at setup time and cached by orchestrators/sellers for real-time use.", + "type": "object", + "properties": { + "list_id": { + "type": "string", + "description": "Unique identifier for this property list" + }, + "name": { + "type": "string", + "description": "Human-readable name for the list" + }, + "description": { + "type": "string", + "description": "Description of the list's purpose" + }, + "principal": { + "type": "string", + "description": "Principal identity that owns this list" + }, + "base_properties": { + "type": "array", + "description": "Array of property sources to evaluate. Each entry is a discriminated union: publisher_tags (publisher_domain + tags), publisher_ids (publisher_domain + property_ids), or identifiers (direct identifiers). If omitted, queries the agent's entire property database.", + "items": { + "$ref": "/schemas/2.6.0/property/base-property-source.json" + } + }, + "filters": { + "$ref": "/schemas/2.6.0/property/property-list-filters.json", + "description": "Dynamic filters applied when resolving the list" + }, + "brand_manifest": { + "$ref": "/schemas/2.6.0/core/brand-manifest.json", + "description": "Brand identity used to automatically apply appropriate rules" + }, + "webhook_url": { + "type": "string", + "format": "uri", + "description": "URL to receive notifications when the resolved list changes" + }, + "cache_duration_hours": { + "type": "integer", + "description": "Recommended cache duration for resolved list. Consumers should re-fetch after this period.", + "minimum": 1, + "default": 24 + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "When the list was created" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "description": "When the list was last modified" + }, + "property_count": { + "type": "integer", + "description": "Number of properties in the resolved list (at time of last resolution)" + } + }, + "required": ["list_id", "name"], + "additionalProperties": false +} diff --git a/dist/schemas/2.6.0/property/update-property-list-request.json b/dist/schemas/2.6.0/property/update-property-list-request.json new file mode 100644 index 0000000000..29368a3e11 --- /dev/null +++ b/dist/schemas/2.6.0/property/update-property-list-request.json @@ -0,0 +1,49 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/2.6.0/property/update-property-list-request.json", + "title": "Update Property List Request", + "description": "Request parameters for updating an existing property list", + "type": "object", + "properties": { + "list_id": { + "type": "string", + "description": "ID of the property list to update" + }, + "name": { + "type": "string", + "description": "New name for the list" + }, + "description": { + "type": "string", + "description": "New description" + }, + "base_properties": { + "type": "array", + "description": "Complete replacement for the base properties list (not a patch). Each entry is a discriminated union: publisher_tags (publisher_domain + tags), publisher_ids (publisher_domain + property_ids), or identifiers (direct identifiers).", + "items": { + "$ref": "/schemas/2.6.0/property/base-property-source.json" + } + }, + "filters": { + "$ref": "/schemas/2.6.0/property/property-list-filters.json", + "description": "Complete replacement for the filters (not a patch)" + }, + "brand_manifest": { + "$ref": "/schemas/2.6.0/core/brand-manifest.json", + "description": "Update brand identity and requirements" + }, + "webhook_url": { + "type": "string", + "format": "uri", + "description": "Update the webhook URL for list change notifications (set to empty string to remove)" + }, + "context": { + "$ref": "/schemas/2.6.0/core/context.json" + }, + "ext": { + "$ref": "/schemas/2.6.0/core/ext.json" + } + }, + "required": ["list_id"], + "additionalProperties": false +} diff --git a/dist/schemas/2.6.0/property/update-property-list-response.json b/dist/schemas/2.6.0/property/update-property-list-response.json new file mode 100644 index 0000000000..435d4c7f09 --- /dev/null +++ b/dist/schemas/2.6.0/property/update-property-list-response.json @@ -0,0 +1,18 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/2.6.0/property/update-property-list-response.json", + "title": "Update Property List Response", + "description": "Response payload for update_property_list task", + "type": "object", + "properties": { + "list": { + "$ref": "/schemas/2.6.0/property/property-list.json", + "description": "The updated property list" + }, + "ext": { + "$ref": "/schemas/2.6.0/core/ext.json" + } + }, + "required": ["list"], + "additionalProperties": false +} diff --git a/dist/schemas/2.6.0/property/validate-property-delivery-request.json b/dist/schemas/2.6.0/property/validate-property-delivery-request.json new file mode 100644 index 0000000000..39638929b8 --- /dev/null +++ b/dist/schemas/2.6.0/property/validate-property-delivery-request.json @@ -0,0 +1,32 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/2.6.0/property/validate-property-delivery-request.json", + "title": "Validate Property Delivery Request", + "description": "Request payload for validate_property_delivery task. Validates delivery records against a property list to determine compliance.", + "type": "object", + "properties": { + "list_id": { + "type": "string", + "description": "ID of the property list to validate against" + }, + "records": { + "type": "array", + "description": "Delivery records to validate. Each record represents impressions delivered to a property identifier.", + "items": { + "$ref": "/schemas/2.6.0/property/delivery-record.json" + }, + "minItems": 1, + "maxItems": 10000 + }, + "include_compliant": { + "type": "boolean", + "default": false, + "description": "Include compliant records in results (default: only return non_compliant, unmodeled, and unidentified)" + }, + "ext": { + "$ref": "/schemas/2.6.0/core/ext.json" + } + }, + "required": ["list_id", "records"], + "additionalProperties": false +} diff --git a/dist/schemas/2.6.0/property/validate-property-delivery-response.json b/dist/schemas/2.6.0/property/validate-property-delivery-response.json new file mode 100644 index 0000000000..ced6ba0e0e --- /dev/null +++ b/dist/schemas/2.6.0/property/validate-property-delivery-response.json @@ -0,0 +1,167 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/2.6.0/property/validate-property-delivery-response.json", + "title": "Validate Property Delivery Response", + "description": "Response payload for validate_property_delivery task. Returns aggregate compliance statistics and per-record validation results.", + "type": "object", + "properties": { + "list_id": { + "type": "string", + "description": "ID of the property list validated against" + }, + "summary": { + "type": "object", + "description": "Aggregate validation statistics", + "properties": { + "total_records": { + "type": "integer", + "description": "Total number of records validated" + }, + "total_impressions": { + "type": "integer", + "description": "Total impressions across all records" + }, + "compliant_records": { + "type": "integer", + "description": "Number of records with compliant status" + }, + "compliant_impressions": { + "type": "integer", + "description": "Impressions from compliant records" + }, + "non_compliant_records": { + "type": "integer", + "description": "Number of records with non_compliant status" + }, + "non_compliant_impressions": { + "type": "integer", + "description": "Impressions from non_compliant records" + }, + "not_covered_records": { + "type": "integer", + "description": "Number of records where identifier was recognized but no data available" + }, + "not_covered_impressions": { + "type": "integer", + "description": "Impressions from not_covered records" + }, + "unidentified_records": { + "type": "integer", + "description": "Number of records where identifier type was not resolvable" + }, + "unidentified_impressions": { + "type": "integer", + "description": "Impressions from unidentified records" + } + }, + "required": [ + "total_records", + "total_impressions", + "compliant_records", + "compliant_impressions", + "non_compliant_records", + "non_compliant_impressions", + "not_covered_records", + "not_covered_impressions", + "unidentified_records", + "unidentified_impressions" + ], + "additionalProperties": false + }, + "aggregate": { + "type": "object", + "description": "Optional aggregate measurements computed by the governance agent. Format and meaning are agent-specific.", + "properties": { + "score": { + "type": "number", + "description": "Numeric score (0-100 scale typical, but agent-defined)" + }, + "grade": { + "type": "string", + "description": "Letter grade or category (e.g., 'A+', 'B-', 'Gold', 'Compliant')" + }, + "label": { + "type": "string", + "description": "Human-readable summary (e.g., '85% compliant', 'High quality')" + }, + "methodology_url": { + "type": "string", + "format": "uri", + "description": "URL explaining how this aggregate was calculated" + } + }, + "additionalProperties": true + }, + "authorization_summary": { + "type": "object", + "description": "Aggregate authorization statistics. Only present if any records included sales_agent_url.", + "properties": { + "records_checked": { + "type": "integer", + "description": "Number of records with sales_agent_url provided" + }, + "impressions_checked": { + "type": "integer", + "description": "Total impressions from records with sales_agent_url" + }, + "authorized_records": { + "type": "integer", + "description": "Number of records where sales agent was authorized" + }, + "authorized_impressions": { + "type": "integer", + "description": "Impressions from authorized records" + }, + "unauthorized_records": { + "type": "integer", + "description": "Number of records where sales agent was NOT authorized" + }, + "unauthorized_impressions": { + "type": "integer", + "description": "Impressions from unauthorized records" + }, + "unknown_records": { + "type": "integer", + "description": "Number of records where authorization could not be determined (adagents.json unavailable)" + }, + "unknown_impressions": { + "type": "integer", + "description": "Impressions from records where authorization could not be determined" + } + }, + "required": [ + "records_checked", + "impressions_checked", + "authorized_records", + "authorized_impressions", + "unauthorized_records", + "unauthorized_impressions", + "unknown_records", + "unknown_impressions" + ], + "additionalProperties": false + }, + "results": { + "type": "array", + "description": "Per-record validation results. By default only includes non_compliant and unknown records. Set include_compliant=true to include all records.", + "items": { + "$ref": "/schemas/2.6.0/property/validation-result.json" + } + }, + "validated_at": { + "type": "string", + "format": "date-time", + "description": "Timestamp when validation was performed" + }, + "list_resolved_at": { + "type": "string", + "format": "date-time", + "description": "Timestamp of the property list resolution used for validation" + }, + "ext": { + "$ref": "/schemas/2.6.0/core/ext.json" + } + }, + "required": ["list_id", "summary", "results", "validated_at"], + "additionalProperties": false +} diff --git a/dist/schemas/2.6.0/property/validation-result.json b/dist/schemas/2.6.0/property/validation-result.json new file mode 100644 index 0000000000..db1845ee8c --- /dev/null +++ b/dist/schemas/2.6.0/property/validation-result.json @@ -0,0 +1,79 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/2.6.0/property/validation-result.json", + "title": "Validation Result", + "description": "Result of validating a single delivery record against a property list.", + "type": "object", + "properties": { + "identifier": { + "$ref": "/schemas/2.6.0/core/identifier.json", + "description": "The identifier that was validated" + }, + "record_id": { + "type": "string", + "description": "Client-provided ID from the delivery record (if provided)" + }, + "status": { + "type": "string", + "enum": ["compliant", "non_compliant", "not_covered", "unidentified"], + "description": "Validation status: compliant (in list), non_compliant (not in list), not_covered (identifier recognized but no data available), unidentified (identifier type not resolvable by this governance agent)" + }, + "impressions": { + "type": "integer", + "minimum": 0, + "description": "Number of impressions from this record" + }, + "violations": { + "type": "array", + "description": "Specific violations found (only present for non_compliant records)", + "items": { + "type": "object", + "properties": { + "code": { + "type": "string", + "description": "Machine-readable violation code" + }, + "message": { + "type": "string", + "description": "Human-readable violation description" + }, + "feature_id": { + "type": "string", + "description": "ID of the feature that caused the violation (only present for feature_failed violations)" + }, + "requirement": { + "type": "object", + "description": "The feature requirement that was not met (only present for feature_failed violations)", + "properties": { + "min_value": { + "type": "number", + "description": "Minimum value that was required" + }, + "max_value": { + "type": "number", + "description": "Maximum value that was allowed" + }, + "allowed_values": { + "type": "array", + "description": "Values that would have been acceptable", + "items": {} + } + }, + "additionalProperties": false + } + }, + "required": ["code", "message"], + "additionalProperties": false + } + }, + "authorization": { + "$ref": "/schemas/2.6.0/property/authorization-result.json", + "description": "Authorization validation result (only present if sales_agent_url was provided in the delivery record)" + }, + "ext": { + "$ref": "/schemas/2.6.0/core/ext.json" + } + }, + "required": ["identifier", "status", "impressions"], + "additionalProperties": false +} diff --git a/dist/schemas/2.6.0/protocols/adcp-extension.json b/dist/schemas/2.6.0/protocols/adcp-extension.json index 3d31caf104..07ca8f429e 100644 --- a/dist/schemas/2.6.0/protocols/adcp-extension.json +++ b/dist/schemas/2.6.0/protocols/adcp-extension.json @@ -1,14 +1,14 @@ { "$schema": "http://json-schema.org/draft-07/schema#", "$id": "/schemas/2.6.0/protocols/adcp-extension.json", - "title": "AdCP Agent Card Extension", - "description": "Extension metadata for agent cards (MCP and A2A) declaring AdCP version and supported protocol domains", + "title": "AdCP Agent Card Extension Params", + "description": "Parameters for declaring AdCP support in agent discovery. For A2A, use in extensions[].params. For MCP, use in _meta['adcontextprotocol.org'].", "type": "object", "properties": { "adcp_version": { "type": "string", "pattern": "^\\d+\\.\\d+\\.\\d+$", - "description": "Semantic version of the AdCP specification this agent implements (e.g., '2.4.0')" + "description": "Semantic version of the AdCP specification this agent implements (e.g., '2.5.0'). Extension schemas are versioned along with the AdCP spec." }, "protocols_supported": { "type": "array", @@ -23,6 +23,16 @@ "minItems": 1, "uniqueItems": true, "description": "AdCP protocol domains supported by this agent. At least one must be specified." + }, + "extensions_supported": { + "type": "array", + "description": "Typed extensions this agent supports. Each extension has a formal schema in /schemas/extensions/. Extension version is determined by adcp_version.", + "items": { + "type": "string", + "pattern": "^[a-z][a-z0-9_]*$", + "description": "Extension namespace (e.g., 'sustainability'). Must be lowercase alphanumeric with underscores." + }, + "uniqueItems": true } }, "required": [ From 74c4acead24fff1b7dd7028a08bcb98aaf59b427 Mon Sep 17 00:00:00 2001 From: Brian O'Kelley Date: Fri, 16 Jan 2026 14:05:29 -0500 Subject: [PATCH 18/34] refactor: replace creative_ids with creative_assignments (#794) * docs: clarify inline creative handling (Option B) - create_media_buy and update_media_buy creatives array creates NEW creatives only - Add CREATIVE_ID_EXISTS error code when creative_id already exists in library - Add CREATIVE_IN_ACTIVE_DELIVERY error code to sync_creatives - Clarify that sync_creatives is the canonical way to update/delete creatives - Document upsert semantics with active delivery protection Co-Authored-By: Claude Opus 4.5 * refactor: replace creative_ids with creative_assignments - Remove creative_ids from package-request.json and update-media-buy-request.json - Use creative_assignments for assigning existing library creatives (supports optional weight/placement_ids) - Update documentation and examples to use creative_assignments - Clarify delete_missing in sync_creatives cannot delete creatives in active delivery Co-Authored-By: Claude Opus 4.5 * refactor: Extract package update schema and add reporting_webhook support Split package schema into three clear variants: - package-request.json (create): Full package with product_id, format_ids, pricing_option_id - package-update.json (update): Only updatable fields, omits immutable fields - package.json (response): Reflects current package state Adds reporting_webhook to update_media_buy, enabling modification of reporting configuration after campaign creation. Keeps push_notification_config separate for async operation notifications. This unifies schema definitions, eliminates duplication, and resolves the issue where reporting setup could not be updated post-launch without recreating the media buy. Co-Authored-By: Claude Haiku 4.5 * refactor: Extract reporting_webhook to shared schema - Create /schemas/core/reporting-webhook.json with webhook config for automated reporting delivery - Update create-media-buy-request.json to use $ref - Update update-media-buy-request.json to use $ref Co-Authored-By: Claude Opus 4.5 * fix: Address code review feedback - Fix CREATIVE_ID_EXISTS resolution to use creative_assignments (not creative_ids) - Update Next Steps in update_media_buy to reference creative assignments - Use $ref for available-metric enum in reporting-webhook.json Co-Authored-By: Claude Opus 4.5 --------- Co-authored-by: Claude Opus 4.5 --- .changeset/loud-bushes-train.md | 15 ++++ .../task-reference/create_media_buy.mdx | 6 +- .../task-reference/sync_creatives.mdx | 8 +- .../task-reference/update_media_buy.mdx | 45 ++++++++--- .../source/core/reporting-webhook.json | 67 ++++++++++++++++ static/schemas/source/index.json | 4 + .../media-buy/create-media-buy-request.json | 76 +----------------- .../source/media-buy/package-request.json | 8 +- .../source/media-buy/package-update.json | 73 +++++++++++++++++ .../media-buy/update-media-buy-request.json | 78 ++----------------- 10 files changed, 216 insertions(+), 164 deletions(-) create mode 100644 .changeset/loud-bushes-train.md create mode 100644 static/schemas/source/core/reporting-webhook.json create mode 100644 static/schemas/source/media-buy/package-update.json diff --git a/.changeset/loud-bushes-train.md b/.changeset/loud-bushes-train.md new file mode 100644 index 0000000000..78db9bd2ba --- /dev/null +++ b/.changeset/loud-bushes-train.md @@ -0,0 +1,15 @@ +--- +"adcontextprotocol": minor +--- + +Clarify creative handling in media buy operations: + +**Breaking:** Replace `creative_ids` with `creative_assignments` in `create_media_buy` and `update_media_buy` +- `creative_assignments` supports optional `weight` and `placement_ids` for granular control +- Simple assignment: `{ "creative_id": "my_creative" }` (weight/placement optional) +- Advanced assignment: `{ "creative_id": "my_creative", "weight": 60, "placement_ids": ["p1"] }` + +**Clarifications:** +- `creatives` array creates NEW creatives only (add `CREATIVE_ID_EXISTS` error) +- `delete_missing` in sync_creatives cannot delete creatives in active delivery (`CREATIVE_IN_ACTIVE_DELIVERY` error) +- Document that existing library creatives should be managed via `sync_creatives` diff --git a/docs/media-buy/task-reference/create_media_buy.mdx b/docs/media-buy/task-reference/create_media_buy.mdx index 80001c91ba..fa138364b3 100644 --- a/docs/media-buy/task-reference/create_media_buy.mdx +++ b/docs/media-buy/task-reference/create_media_buy.mdx @@ -182,8 +182,8 @@ npx adcp \ | `pacing` | string | No | `"even"` (default), `"asap"`, or `"front_loaded"` | | `bid_price` | number | No | Bid price for auction pricing (required when `is_fixed` is false) | | `targeting_overlay` | TargetingOverlay | No | Additional targeting criteria (see [Targeting](/docs/media-buy/advanced-topics/targeting)) | -| `creative_ids` | string[] | No | Existing library creative IDs to assign | -| `creatives` | CreativeAsset[] | No | Full creative objects to upload and assign | +| `creative_assignments` | CreativeAssignment[] | No | Assign existing library creatives with optional weights and placement targeting | +| `creatives` | CreativeAsset[] | No | Upload new creative assets and assign (`creative_id` must not already exist in library) | ## Response @@ -550,6 +550,7 @@ Common errors and resolutions: | `TARGETING_TOO_NARROW` | Targeting yields zero inventory | Broaden geographic or audience criteria | | `POLICY_VIOLATION` | Brand/product violates policy | Review publisher's content policies | | `INVALID_PRICING_OPTION` | pricing_option_id not found | Use ID from product's `pricing_options` | +| `CREATIVE_ID_EXISTS` | Creative ID already exists in library | Use a different `creative_id`, assign existing creatives via `creative_assignments`, or update via `sync_creatives` | Example error response: @@ -1025,6 +1026,7 @@ For complete async handling patterns, see [Task Management](/docs/protocols/task - AXE segments enable advanced audience targeting - Pending states (`working`, `submitted`) are normal, not errors - Orchestrators MUST handle pending states as part of normal workflow +- **Inline creatives**: The `creatives` array creates NEW creatives only. To update existing creatives, use [`sync_creatives`](/docs/media-buy/task-reference/sync_creatives). To assign existing library creatives, use `creative_assignments` instead. ## Policy Compliance diff --git a/docs/media-buy/task-reference/sync_creatives.mdx b/docs/media-buy/task-reference/sync_creatives.mdx index e5133c59d2..30a5182714 100644 --- a/docs/media-buy/task-reference/sync_creatives.mdx +++ b/docs/media-buy/task-reference/sync_creatives.mdx @@ -106,7 +106,7 @@ asyncio.run(main()) | `assignments` | object | No | Map of creative_id to array of package_ids for bulk assignment | | `dry_run` | boolean | No | When true, preview changes without applying them (default: false) | | `validation_mode` | string | No | Validation strictness: `"strict"` (default) or `"lenient"` | -| `delete_missing` | boolean | No | When true, creatives not in this sync are archived (default: false) | +| `delete_missing` | boolean | No | When true, creatives not in this sync are archived (default: false). Cannot delete creatives assigned to active, non-paused packages. | ### Creative Object @@ -651,11 +651,11 @@ The operation status (`completed`) means the review process finished. Individual | `PACKAGE_NOT_FOUND` | Package ID doesn't exist in media buy | Verify `package_id` from `create_media_buy` response | | `BRAND_SAFETY_VIOLATION` | Creative failed brand safety scan | Review content against publisher's brand safety guidelines | | `FORMAT_MISMATCH` | Assets don't match format requirements | Verify asset types and specifications match format definition | -| `DUPLICATE_CREATIVE_ID` | Creative ID already exists in different media buy | Use unique `creative_id` or sync to correct media buy | +| `CREATIVE_IN_ACTIVE_DELIVERY` | Creative is assigned to an active, non-paused package (blocks updates and `delete_missing` deletions) | Pause the package first, or create a new creative version | ## Best Practices -1. **Use upsert semantics** - Same `creative_id` updates existing creative rather than creating duplicates. This allows iterative creative development. +1. **Use upsert semantics** - Same `creative_id` updates existing creative rather than creating duplicates. This allows iterative creative development. Note: updates are blocked for creatives in active delivery (see #7). 2. **Validate first** - Use `dry_run: true` to catch errors before actual upload. This saves bandwidth and processing time. @@ -667,6 +667,8 @@ The operation status (`completed`) means the review process finished. Individual 6. **Check format support** - Use `list_creative_formats` to verify product supports your creative formats before uploading. +7. **Active delivery protection** - Creatives assigned to active, non-paused packages cannot be updated or deleted via `delete_missing`. Pause the package first, unassign the creative via `update_media_buy`, or create a new creative with a different `creative_id`. + ## Next Steps - [list_creative_formats](/docs/media-buy/task-reference/list_creative_formats) - Check supported formats before upload diff --git a/docs/media-buy/task-reference/update_media_buy.mdx b/docs/media-buy/task-reference/update_media_buy.mdx index 237b6847e7..0dd78ea270 100644 --- a/docs/media-buy/task-reference/update_media_buy.mdx +++ b/docs/media-buy/task-reference/update_media_buy.mdx @@ -149,11 +149,25 @@ asyncio.run(create_and_pause_campaign()) | `end_time` | string | No | Updated campaign end time | | `paused` | boolean | No | Pause/resume entire media buy (`true` = paused, `false` = active) | | `packages` | PackageUpdate[] | No | Package-level updates (see below) | -| `creatives` | CreativeAsset[] | No | Upload and assign new creative assets inline | -| `creative_assignments` | CreativeAssignment[] | No | Update creative rotation weights and placement targeting | +| `reporting_webhook` | object | No | Update reporting webhook configuration (see below) | +| `push_notification_config` | object | No | Webhook for async operation notifications | *Either `media_buy_id` OR `buyer_ref` is required (not both) +### Reporting Webhook Object + +Configure automated delivery reporting for this media buy: + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `url` | string | Yes | Webhook endpoint URL | +| `authentication` | object | Yes | Auth config with `schemes` and `credentials` | +| `reporting_frequency` | string | Yes | `hourly`, `daily`, or `monthly` | +| `requested_metrics` | string[] | No | Specific metrics to include (defaults to all) | +| `token` | string | No | Client token for validation (min 16 chars) | + +**Note**: `reporting_webhook` configures ongoing campaign reporting. `push_notification_config` is for async operation notifications (e.g., "notify me when this update completes"). + ### Package Update Object | Parameter | Type | Description | @@ -166,7 +180,8 @@ asyncio.run(create_and_pause_campaign()) | `pacing` | string | Updated pacing strategy | | `bid_price` | number | Updated bid price (auction products only) | | `targeting_overlay` | TargetingOverlay | Updated targeting restrictions | -| `creative_ids` | string[] | Replace assigned creatives | +| `creative_assignments` | CreativeAssignment[] | Replace assigned creatives with optional weights and placement targeting | +| `creatives` | CreativeAsset[] | Upload and assign new creatives inline (must not exist in library) | *Either `package_id` OR `buyer_ref` is required for each package update @@ -372,7 +387,7 @@ asyncio.run(update_targeting()) ### Replace Creatives -Swap out creative assets for a package: +Swap out creative assignments for a package: @@ -384,7 +399,10 @@ const result = await testAgent.updateMediaBuy({ media_buy_id: 'mb_12345', packages: [{ buyer_ref: 'ctv_package', - creative_ids: ['creative_video_v2', 'creative_display_v2'] + creative_assignments: [ + { creative_id: 'creative_video_v2' }, + { creative_id: 'creative_display_v2', weight: 60 } + ] }] }); @@ -415,7 +433,10 @@ async def replace_creatives(): packages=[ { 'buyer_ref': 'ctv_package', - 'creative_ids': ['creative_video_v2', 'creative_display_v2'] + 'creative_assignments': [ + {'creative_id': 'creative_video_v2'}, + {'creative_id': 'creative_display_v2', 'weight': 60} + ] } ] ) @@ -513,6 +534,7 @@ asyncio.run(update_multiple_packages()) ✅ **Can update:** - Start/end times (subject to seller approval) - Campaign status (active/paused) +- Reporting webhook configuration (URL, frequency, metrics) ❌ **Cannot update:** - Media buy ID @@ -548,6 +570,7 @@ Common errors and resolutions: | `BUDGET_INSUFFICIENT` | New budget below minimum | Increase budget amount | | `POLICY_VIOLATION` | Update violates content policy | Review policy requirements | | `INVALID_STATE` | Operation not allowed in current state | Check campaign status | +| `CREATIVE_ID_EXISTS` | Creative ID already exists in library | Use a different `creative_id`, assign existing creatives via `creative_assignments`, or update via `sync_creatives` | Example error response: @@ -596,13 +619,16 @@ Only specified fields are updated - omitted fields remain unchanged: } ``` -**Array replacement**: When updating arrays (like `creative_ids`), provide the complete new array: +**Array replacement**: When updating arrays (like `creative_assignments`), provide the complete new array: ```json { "packages": [{ "buyer_ref": "ctv_package", - "creative_ids": ["creative_video_v2", "creative_display_v2"] + "creative_assignments": [ + { "creative_id": "creative_video_v2" }, + { "creative_id": "creative_display_v2", "weight": 60 } + ] }] } ``` @@ -678,13 +704,14 @@ Check `affected_packages` in response to confirm changes were applied correctly. - Pending states (`working`, `submitted`) are normal, not errors - Orchestrators MUST handle pending states as part of normal workflow - `implementation_date` indicates when changes take effect (null if pending approval) +- **Inline creatives**: The `creatives` array creates NEW creatives only. To update existing creatives, use [`sync_creatives`](/docs/media-buy/task-reference/sync_creatives). To assign existing library creatives, use `creative_assignments` in the Package Update object. ## Next Steps After updating a media buy: 1. **Verify Changes**: Use [`get_media_buy_delivery`](/docs/media-buy/task-reference/get_media_buy_delivery) to confirm updates -2. **Upload New Creatives**: Use [`sync_creatives`](/docs/media-buy/task-reference/sync_creatives) if creative_ids changed +2. **Upload New Creatives**: Use [`sync_creatives`](/docs/media-buy/task-reference/sync_creatives) if creative assignments changed 3. **Monitor Performance**: Track impact of changes on campaign metrics 4. **Optimize Further**: Use [`provide_performance_feedback`](/docs/media-buy/task-reference/provide_performance_feedback) for ongoing optimization diff --git a/static/schemas/source/core/reporting-webhook.json b/static/schemas/source/core/reporting-webhook.json new file mode 100644 index 0000000000..cb9a295533 --- /dev/null +++ b/static/schemas/source/core/reporting-webhook.json @@ -0,0 +1,67 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/core/reporting-webhook.json", + "title": "Reporting Webhook", + "description": "Webhook configuration for automated reporting delivery. Configures where and how campaign performance reports are sent.", + "type": "object", + "properties": { + "url": { + "type": "string", + "format": "uri", + "description": "Webhook endpoint URL for reporting notifications" + }, + "token": { + "type": "string", + "description": "Optional client-provided token for webhook validation. Echoed back in webhook payload to validate request authenticity.", + "minLength": 16 + }, + "authentication": { + "type": "object", + "description": "Authentication configuration for webhook delivery (A2A-compatible)", + "properties": { + "schemes": { + "type": "array", + "description": "Array of authentication schemes. Supported: ['Bearer'] for simple token auth, ['HMAC-SHA256'] for signature verification (recommended for production)", + "items": { + "$ref": "/schemas/enums/auth-scheme.json" + }, + "minItems": 1, + "maxItems": 1 + }, + "credentials": { + "type": "string", + "description": "Credentials for authentication. For Bearer: token sent in Authorization header. For HMAC-SHA256: shared secret used to generate signature. Minimum 32 characters. Exchanged out-of-band during onboarding.", + "minLength": 32 + } + }, + "required": [ + "schemes", + "credentials" + ], + "additionalProperties": false + }, + "reporting_frequency": { + "type": "string", + "enum": [ + "hourly", + "daily", + "monthly" + ], + "description": "Frequency for automated reporting delivery. Must be supported by all products in the media buy." + }, + "requested_metrics": { + "type": "array", + "description": "Optional list of metrics to include in webhook notifications. If omitted, all available metrics are included. Must be subset of product's available_metrics.", + "items": { + "$ref": "/schemas/enums/available-metric.json" + }, + "uniqueItems": true + } + }, + "required": [ + "url", + "authentication", + "reporting_frequency" + ], + "additionalProperties": true +} diff --git a/static/schemas/source/index.json b/static/schemas/source/index.json index 635683aced..36eec37f3f 100644 --- a/static/schemas/source/index.json +++ b/static/schemas/source/index.json @@ -411,6 +411,10 @@ "package-request": { "$ref": "/schemas/media-buy/package-request.json", "description": "Package configuration for media buy creation - used within create_media_buy request" + }, + "package-update": { + "$ref": "/schemas/media-buy/package-update.json", + "description": "Package update configuration for update_media_buy - identifies package and specifies fields to modify" } }, "tasks": { diff --git a/static/schemas/source/media-buy/create-media-buy-request.json b/static/schemas/source/media-buy/create-media-buy-request.json index 3e83f44baf..47f5aa5822 100644 --- a/static/schemas/source/media-buy/create-media-buy-request.json +++ b/static/schemas/source/media-buy/create-media-buy-request.json @@ -33,80 +33,8 @@ "description": "Campaign end date/time in ISO 8601 format" }, "reporting_webhook": { - "$comment": "Fields url, token, and authentication mirror push-notification-config.json. Inlined here because allOf + additionalProperties:false doesn't work in JSON Schema (additionalProperties can't see $ref properties). See CLAUDE.md 'Avoiding allOf with additionalProperties'.", - "type": "object", - "description": "Optional webhook configuration for automated reporting delivery. Combines push_notification_config structure with reporting-specific fields.", - "properties": { - "url": { - "type": "string", - "format": "uri", - "description": "Webhook endpoint URL for reporting notifications" - }, - "token": { - "type": "string", - "description": "Optional client-provided token for webhook validation. Echoed back in webhook payload to validate request authenticity.", - "minLength": 16 - }, - "authentication": { - "type": "object", - "description": "Authentication configuration for webhook delivery (A2A-compatible)", - "properties": { - "schemes": { - "type": "array", - "description": "Array of authentication schemes. Supported: ['Bearer'] for simple token auth, ['HMAC-SHA256'] for signature verification (recommended for production)", - "items": { - "$ref": "/schemas/enums/auth-scheme.json" - }, - "minItems": 1, - "maxItems": 1 - }, - "credentials": { - "type": "string", - "description": "Credentials for authentication. For Bearer: token sent in Authorization header. For HMAC-SHA256: shared secret used to generate signature. Minimum 32 characters. Exchanged out-of-band during onboarding.", - "minLength": 32 - } - }, - "required": [ - "schemes", - "credentials" - ], - "additionalProperties": false - }, - "reporting_frequency": { - "type": "string", - "enum": [ - "hourly", - "daily", - "monthly" - ], - "description": "Frequency for automated reporting delivery. Must be supported by all products in the media buy." - }, - "requested_metrics": { - "type": "array", - "description": "Optional list of metrics to include in webhook notifications. If omitted, all available metrics are included. Must be subset of product's available_metrics.", - "items": { - "type": "string", - "enum": [ - "impressions", - "spend", - "clicks", - "ctr", - "video_completions", - "completion_rate", - "conversions", - "viewability", - "engagement_rate" - ] - }, - "uniqueItems": true - } - }, - "required": [ - "url", - "authentication", - "reporting_frequency" - ], - "additionalProperties": true + "$ref": "/schemas/core/reporting-webhook.json", + "description": "Optional webhook configuration for automated reporting delivery" }, "context": { "$ref": "/schemas/core/context.json" diff --git a/static/schemas/source/media-buy/package-request.json b/static/schemas/source/media-buy/package-request.json index c09f6fa5f0..a1e94bcaa2 100644 --- a/static/schemas/source/media-buy/package-request.json +++ b/static/schemas/source/media-buy/package-request.json @@ -51,16 +51,16 @@ "targeting_overlay": { "$ref": "/schemas/core/targeting.json" }, - "creative_ids": { + "creative_assignments": { "type": "array", - "description": "Creative IDs to assign to this package at creation time (references existing library creatives)", + "description": "Assign existing library creatives to this package with optional weights and placement targeting", "items": { - "type": "string" + "$ref": "/schemas/core/creative-assignment.json" } }, "creatives": { "type": "array", - "description": "Full creative objects to upload and assign to this package at creation time (alternative to creative_ids - creatives will be added to library). Supports both static and generative creatives.", + "description": "Upload new creative assets and assign to this package (creatives will be added to library). Use creative_assignments instead for existing library creatives.", "items": { "$ref": "/schemas/core/creative-asset.json" }, diff --git a/static/schemas/source/media-buy/package-update.json b/static/schemas/source/media-buy/package-update.json new file mode 100644 index 0000000000..a93f87834a --- /dev/null +++ b/static/schemas/source/media-buy/package-update.json @@ -0,0 +1,73 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/media-buy/package-update.json", + "title": "Package Update", + "description": "Package update configuration for update_media_buy. Identifies package by package_id or buyer_ref and specifies fields to modify. Fields not present are left unchanged. Note: product_id, format_ids, and pricing_option_id cannot be changed after creation.", + "type": "object", + "properties": { + "package_id": { + "type": "string", + "description": "Publisher's ID of package to update" + }, + "buyer_ref": { + "type": "string", + "description": "Buyer's reference for the package to update" + }, + "budget": { + "type": "number", + "description": "Updated budget allocation for this package in the currency specified by the pricing option", + "minimum": 0 + }, + "pacing": { + "$ref": "/schemas/enums/pacing.json" + }, + "bid_price": { + "type": "number", + "description": "Updated bid price for auction-based pricing options (only applies when pricing_option is auction-based)", + "minimum": 0 + }, + "impressions": { + "type": "number", + "description": "Updated impression goal for this package", + "minimum": 0 + }, + "paused": { + "type": "boolean", + "description": "Pause/resume specific package (true = paused, false = active)" + }, + "targeting_overlay": { + "$ref": "/schemas/core/targeting.json" + }, + "creative_assignments": { + "type": "array", + "description": "Replace creative assignments for this package with optional weights and placement targeting. Uses replacement semantics - omit to leave assignments unchanged.", + "items": { + "$ref": "/schemas/core/creative-assignment.json" + } + }, + "creatives": { + "type": "array", + "description": "Upload new creative assets and assign to this package (creatives will be added to library). Use creative_assignments instead for existing library creatives.", + "items": { + "$ref": "/schemas/core/creative-asset.json" + }, + "maxItems": 100 + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "oneOf": [ + { + "required": [ + "package_id" + ] + }, + { + "required": [ + "buyer_ref" + ] + } + ], + "additionalProperties": true +} diff --git a/static/schemas/source/media-buy/update-media-buy-request.json b/static/schemas/source/media-buy/update-media-buy-request.json index e88dd17b5e..67c108a10f 100644 --- a/static/schemas/source/media-buy/update-media-buy-request.json +++ b/static/schemas/source/media-buy/update-media-buy-request.json @@ -29,82 +29,16 @@ "type": "array", "description": "Package-specific updates", "items": { - "type": "object", - "properties": { - "package_id": { - "type": "string", - "description": "Publisher's ID of package to update" - }, - "buyer_ref": { - "type": "string", - "description": "Buyer's reference for the package to update" - }, - "budget": { - "type": "number", - "description": "Updated budget allocation for this package in the currency specified by the pricing option", - "minimum": 0 - }, - "pacing": { - "$ref": "/schemas/enums/pacing.json" - }, - "bid_price": { - "type": "number", - "description": "Updated bid price for auction-based pricing options (only applies when pricing_option is auction-based)", - "minimum": 0 - }, - "impressions": { - "type": "number", - "description": "Updated impression goal for this package", - "minimum": 0 - }, - "paused": { - "type": "boolean", - "description": "Pause/resume specific package (true = paused, false = active)" - }, - "targeting_overlay": { - "$ref": "/schemas/core/targeting.json" - }, - "creative_ids": { - "type": "array", - "description": "Update creative assignments (references existing library creatives)", - "items": { - "type": "string" - } - }, - "creatives": { - "type": "array", - "description": "Full creative objects to upload and assign to this package (alternative to creative_ids - creatives will be added to library). Supports both static and generative creatives.", - "items": { - "$ref": "/schemas/core/creative-asset.json" - }, - "maxItems": 100 - }, - "creative_assignments": { - "type": "array", - "description": "Full creative assignment objects with weights and placement targeting (alternative to creative_ids - provides granular control over weights and placement targeting). Uses replacement semantics like creative_ids.", - "items": { - "$ref": "/schemas/core/creative-assignment.json" - } - } - }, - "oneOf": [ - { - "required": [ - "package_id" - ] - }, - { - "required": [ - "buyer_ref" - ] - } - ], - "additionalProperties": true + "$ref": "/schemas/media-buy/package-update.json" } }, + "reporting_webhook": { + "$ref": "/schemas/core/reporting-webhook.json", + "description": "Optional webhook configuration for automated reporting delivery. Updates the reporting configuration for this media buy." + }, "push_notification_config": { "$ref": "/schemas/core/push-notification-config.json", - "description": "Optional webhook configuration for async update notifications. Publisher will send webhook when update completes if operation takes longer than immediate response time." + "description": "Optional webhook configuration for async update notifications. Publisher will send webhook when update completes if operation takes longer than immediate response time. This is separate from reporting_webhook which configures ongoing campaign reporting." }, "context": { "$ref": "/schemas/core/context.json" From d3b5048abb92bf21e9a080b2daff5011a79d35ea Mon Sep 17 00:00:00 2001 From: Brian O'Kelley Date: Sun, 18 Jan 2026 09:11:45 -0500 Subject: [PATCH 19/34] feat: Add privacy_policy_url to brand manifest and adagents.json (#801) Enables consumer consent flows by providing a link to advertiser/publisher privacy policies. AI platforms can use this to present explicit privacy choices to users before data handoff. Works alongside MyTerms/IEEE P7012 discovery for machine-readable privacy terms - the privacy_policy_url serves as the human-readable fallback. Changes: - Add privacy_policy_url field to brand-manifest.json schema - Add privacy_policy_url field to adagents.json contact object - Add Privacy Integration section to brand manifest documentation - Update adagents.json documentation with new field Co-authored-by: Claude Opus 4.5 --- .changeset/hip-numbers-train.md | 7 +++++ docs/creative/brand-manifest.mdx | 29 +++++++++++++++++++ static/schemas/source/adagents.json | 8 ++++- .../schemas/source/core/brand-manifest.json | 6 ++++ .../capability-discovery/adagents.mdx | 4 ++- 5 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 .changeset/hip-numbers-train.md diff --git a/.changeset/hip-numbers-train.md b/.changeset/hip-numbers-train.md new file mode 100644 index 0000000000..52ccb26a2e --- /dev/null +++ b/.changeset/hip-numbers-train.md @@ -0,0 +1,7 @@ +--- +"adcontextprotocol": minor +--- + +Add privacy_policy_url field to brand manifest and adagents.json schemas + +Enables consumer consent flows by providing a link to advertiser/publisher privacy policies. AI platforms can use this to present explicit privacy choices to users before data handoff. Works alongside MyTerms/IEEE P7012 discovery for machine-readable privacy terms. diff --git a/docs/creative/brand-manifest.mdx b/docs/creative/brand-manifest.mdx index 692a6fe993..7729e315ff 100644 --- a/docs/creative/brand-manifest.mdx +++ b/docs/creative/brand-manifest.mdx @@ -22,6 +22,7 @@ Brand manifests solve a key problem: how to efficiently identify advertisers and ### Key Benefits - **Know Your Customer**: Publishers can verify advertisers meet their standards +- **Privacy Transparency**: Link to privacy policy for consumer consent flows - **Minimal Friction**: Start with just a name or URL, expand as needed - **Cacheable**: Same brand manifest reused across all requests - **Standardized**: Consistent format across all AdCP implementations @@ -243,6 +244,7 @@ The structure of the brand manifest object itself (whether provided inline or ho | Field | Type | Description | |-------|------|-------------| | `name` | string | Brand or business name | +| `privacy_policy_url` | string (uri) | URL to the brand's privacy policy for consumer consent flows | | `logos` | Logo[] | Brand logo assets with semantic tags | | `colors` | Colors | Brand color palette (hex format) | | `fonts` | Fonts | Brand typography guidelines | @@ -492,6 +494,33 @@ Enterprise brands with large asset libraries should provide explicit assets: } ``` +## Privacy Integration + +Brand manifests support privacy transparency through the `privacy_policy_url` field. This enables AI platforms to present explicit privacy choices to users before sharing personal data with advertisers. + +### Consumer Consent Flow + +When an AI assistant helps a user engage with an advertiser (booking a flight, making a purchase, etc.), the platform can use the brand manifest's privacy policy URL to: + +1. **Present explicit consent**: "May I share your details with Delta? [View their privacy policy]" +2. **Enable informed decisions**: Users can review data practices before data handoff +3. **Support machine-readable terms**: Works alongside [MyTerms/IEEE P7012](https://myterms.info) for automated privacy negotiation + +### Example with Privacy Policy + +```json +{ + "$schema": "https://adcontextprotocol.org/schemas/v2/core/brand-manifest.json", + "name": "Delta Airlines", + "url": "https://delta.com", + "privacy_policy_url": "https://delta.com/privacy" +} +``` + +### MyTerms Discovery + +For advertisers implementing [IEEE P7012 (MyTerms)](https://myterms.info), AI platforms can discover machine-readable privacy terms from the advertiser's domain (e.g., `/.well-known/myterms`). The brand manifest's `privacy_policy_url` serves as the human-readable fallback and explicit consent path. + ## Evolution and Versioning Brand cards are versioned using the `metadata.version` field: diff --git a/static/schemas/source/adagents.json b/static/schemas/source/adagents.json index bc48225ca6..9a45c1ff3c 100644 --- a/static/schemas/source/adagents.json +++ b/static/schemas/source/adagents.json @@ -70,6 +70,11 @@ "description": "TAG Certified Against Fraud ID for verification (if applicable)", "minLength": 1, "maxLength": 100 + }, + "privacy_policy_url": { + "type": "string", + "format": "uri", + "description": "URL to the entity's privacy policy. Used for consumer consent flows when interacting with this sales agent." } }, "required": [ @@ -350,7 +355,8 @@ "email": "adops@meta.com", "domain": "meta.com", "seller_id": "pub-meta-12345", - "tag_id": "12345" + "tag_id": "12345", + "privacy_policy_url": "https://www.meta.com/privacy/policy" }, "properties": [ { diff --git a/static/schemas/source/core/brand-manifest.json b/static/schemas/source/core/brand-manifest.json index a1f062442c..e5818d2f6b 100644 --- a/static/schemas/source/core/brand-manifest.json +++ b/static/schemas/source/core/brand-manifest.json @@ -10,6 +10,11 @@ "format": "uri", "description": "Primary brand URL for context and asset discovery. Creative agents can infer brand information from this URL." }, + "privacy_policy_url": { + "type": "string", + "format": "uri", + "description": "URL to the brand's privacy policy. Used for consumer consent flows when personal data may be shared with the advertiser. AI platforms can use this to present explicit privacy choices to users before data handoff." + }, "name": { "type": "string", "description": "Brand or business name" @@ -318,6 +323,7 @@ "description": "Full brand manifest with all fields", "data": { "url": "https://acmecorp.com", + "privacy_policy_url": "https://acmecorp.com/privacy", "name": "ACME Corporation", "logos": [ { diff --git a/v2.6-rc/docs/media-buy/capability-discovery/adagents.mdx b/v2.6-rc/docs/media-buy/capability-discovery/adagents.mdx index 442dee1805..e47ea7c934 100644 --- a/v2.6-rc/docs/media-buy/capability-discovery/adagents.mdx +++ b/v2.6-rc/docs/media-buy/capability-discovery/adagents.mdx @@ -65,6 +65,7 @@ The file must be valid JSON with UTF-8 encoding and return HTTP 200 status. - **`domain`** *(optional)*: Primary domain of managing entity - **`seller_id`** *(optional)*: Seller ID from IAB Tech Lab sellers.json - **`tag_id`** *(optional)*: TAG Certified Against Fraud ID + - **`privacy_policy_url`** *(optional)*: URL to entity's privacy policy for consumer consent flows **`properties`** *(optional)*: Array of properties covered by this file (canonical property definitions) @@ -357,7 +358,8 @@ Large network using tags for grouping efficiency: "email": "adops@meta.com", "domain": "meta.com", "seller_id": "pub-meta-12345", - "tag_id": "12345" + "tag_id": "12345", + "privacy_policy_url": "https://www.meta.com/privacy/policy" }, "properties": [ { From abfe9eb622be75856f275fc67efef16b3ebd8b15 Mon Sep 17 00:00:00 2001 From: Brian O'Kelley Date: Sun, 18 Jan 2026 09:44:55 -0500 Subject: [PATCH 20/34] feat: Add OpenAI Commerce integration to brand manifest (#802) Add support for OpenAI's product feed format and agentic checkout specification, enabling AI agents to discover products and complete purchases through a structured API. Includes field mapping guidance from Google Merchant Center to OpenAI's specification. Co-authored-by: Claude Haiku 4.5 --- .changeset/openai-product-feed.md | 9 +++ docs/creative/brand-manifest.mdx | 67 ++++++++++++++++++- .../schemas/source/core/brand-manifest.json | 53 ++++++++++++++- 3 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 .changeset/openai-product-feed.md diff --git a/.changeset/openai-product-feed.md b/.changeset/openai-product-feed.md new file mode 100644 index 0000000000..0252df2dac --- /dev/null +++ b/.changeset/openai-product-feed.md @@ -0,0 +1,9 @@ +--- +"adcontextprotocol": minor +--- + +Add OpenAI Commerce integration to brand manifest + +- Add `openai_product_feed` as a supported feed format for product catalogs +- Add `agentic_checkout` object to enable AI agents to complete purchases via structured checkout APIs +- Document field mapping from Google Merchant Center to OpenAI Product Feed spec diff --git a/docs/creative/brand-manifest.mdx b/docs/creative/brand-manifest.mdx index 7729e315ff..cb80d8f985 100644 --- a/docs/creative/brand-manifest.mdx +++ b/docs/creative/brand-manifest.mdx @@ -327,10 +327,21 @@ The structure of the brand manifest object itself (whether provided inline or ho ```typescript { feed_url: string; // URL to product catalog feed - feed_format?: string; // Format of the product feed (default: "google_merchant_center") + feed_format?: string; // Format: "google_merchant_center" | "facebook_catalog" | "openai_product_feed" | "custom" categories?: string[]; // Product categories available in the catalog last_updated?: string; // When the product catalog was last updated (ISO 8601) update_frequency?: string; // How frequently the catalog is updated + agentic_checkout?: AgenticCheckout; // Optional checkout endpoint configuration +} +``` + +### AgenticCheckout Object + +```typescript +{ + endpoint: string; // Base URL for checkout session API + spec: string; // Checkout API specification (e.g., "openai_agentic_checkout_v1") + supported_payment_providers?: string[]; // Payment providers (e.g., ["stripe", "adyen"]) } ``` @@ -461,7 +472,7 @@ Large retailers should provide product feeds: } ``` -**Supported Feed Formats**: RSS, JSON Feed, Product CSV +**Supported Feed Formats**: Google Merchant Center, Facebook Catalog, [OpenAI Product Feed](https://developers.openai.com/commerce/specs/feed), Custom ### 5. Asset Libraries for Enterprise @@ -521,6 +532,58 @@ When an AI assistant helps a user engage with an advertiser (booking a flight, m For advertisers implementing [IEEE P7012 (MyTerms)](https://myterms.info), AI platforms can discover machine-readable privacy terms from the advertiser's domain (e.g., `/.well-known/myterms`). The brand manifest's `privacy_policy_url` serves as the human-readable fallback and explicit consent path. +## Agentic Commerce Integration + +Brand manifests support integration with AI commerce platforms through the `product_catalog` field. This enables AI agents to discover products and complete purchases on behalf of users. + +### OpenAI Commerce + +For merchants implementing [OpenAI's Commerce specifications](https://developers.openai.com/commerce), the brand manifest provides a bridge: + +```json +{ + "$schema": "https://adcontextprotocol.org/schemas/v2/core/brand-manifest.json", + "name": "Shop Example", + "url": "https://shopexample.com", + "privacy_policy_url": "https://shopexample.com/privacy", + "product_catalog": { + "feed_url": "https://shopexample.com/products.jsonl.gz", + "feed_format": "openai_product_feed", + "update_frequency": "daily", + "agentic_checkout": { + "endpoint": "https://api.shopexample.com/checkout_sessions", + "spec": "openai_agentic_checkout_v1", + "supported_payment_providers": ["stripe", "adyen"] + } + } +} +``` + +**Key fields for OpenAI Commerce:** + +| Field | Description | +|-------|-------------| +| `feed_format: "openai_product_feed"` | Indicates the feed conforms to [OpenAI's Product Feed spec](https://developers.openai.com/commerce/specs/feed) | +| `agentic_checkout.endpoint` | Base URL for [OpenAI's Agentic Checkout API](https://developers.openai.com/commerce/specs/checkout) | +| `agentic_checkout.spec` | Version identifier for the checkout spec | + +### Feed Format Mapping + +If you have an existing Google Merchant Center feed, here's how key fields map to OpenAI's spec: + +| OpenAI Field | Google Merchant Center | Notes | +|--------------|----------------------|-------| +| `item_id` | `id` | Direct mapping | +| `title` | `title` | Direct mapping | +| `description` | `description` | Direct mapping | +| `url` | `link` | Direct mapping | +| `brand` | `brand` | Direct mapping | +| `price` | `price` | OpenAI uses number + currency code | +| `availability` | `availability` | Same enum values | +| `image_url` | `image_link` | Direct mapping | +| `is_eligible_search` | N/A | OpenAI-specific flag | +| `is_eligible_checkout` | N/A | OpenAI-specific flag | + ## Evolution and Versioning Brand cards are versioned using the `metadata.version` field: diff --git a/static/schemas/source/core/brand-manifest.json b/static/schemas/source/core/brand-manifest.json index e5818d2f6b..a77b795f5b 100644 --- a/static/schemas/source/core/brand-manifest.json +++ b/static/schemas/source/core/brand-manifest.json @@ -194,10 +194,11 @@ "enum": [ "google_merchant_center", "facebook_catalog", + "openai_product_feed", "custom" ], "default": "google_merchant_center", - "description": "Format of the product feed" + "description": "Format of the product feed. Use 'openai_product_feed' for feeds conforming to the OpenAI Commerce Product Feed specification." }, "categories": { "type": "array", @@ -220,6 +221,35 @@ "weekly" ], "description": "How frequently the product catalog is updated" + }, + "agentic_checkout": { + "type": "object", + "description": "Agentic checkout endpoint configuration. Enables AI agents to complete purchases on behalf of users through a structured checkout API.", + "properties": { + "endpoint": { + "type": "string", + "format": "uri", + "description": "Base URL for checkout session API (e.g., https://merchant.com/api/checkout_sessions)" + }, + "spec": { + "type": "string", + "enum": [ + "openai_agentic_checkout_v1" + ], + "description": "Checkout API specification implemented by the endpoint" + }, + "supported_payment_providers": { + "type": "array", + "description": "Payment providers supported by this checkout endpoint", + "items": { + "type": "string" + } + } + }, + "required": [ + "endpoint", + "spec" + ] } }, "required": [ @@ -410,6 +440,27 @@ "industry": "technology", "target_audience": "business decision-makers aged 35-55" } + }, + { + "description": "E-commerce brand with OpenAI product feed and agentic checkout", + "data": { + "url": "https://shopexample.com", + "privacy_policy_url": "https://shopexample.com/privacy", + "name": "Shop Example", + "product_catalog": { + "feed_url": "https://shopexample.com/products.jsonl.gz", + "feed_format": "openai_product_feed", + "update_frequency": "daily", + "agentic_checkout": { + "endpoint": "https://api.shopexample.com/checkout_sessions", + "spec": "openai_agentic_checkout_v1", + "supported_payment_providers": [ + "stripe", + "adyen" + ] + } + } + } } ] } From 6afd173b825c4bf943ec528d47af751c8e2f042d Mon Sep 17 00:00:00 2001 From: Brian O'Kelley Date: Sun, 18 Jan 2026 10:42:10 -0500 Subject: [PATCH 21/34] Add Content Standards Protocol (#621) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add Content Standards Protocol for content safety evaluation Introduces the Content Standards Protocol with four tasks: - list_content_features: Discover available content safety features - get_content_standards: Retrieve content safety policies - check_content: Evaluate content context against safety policies - validate_content_delivery: Batch validate delivery records Features use a generic type system (binary, quantitative, categorical) aligned with property governance patterns. Policies use prompt-based evaluation (like Scope3) rather than keyword lists. Standards can be scoped by country, brand, channel, and product. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Simplify content standards policy model - Remove sentiment analysis (subset of suitability) - Clarify brand safety vs suitability distinction: - Safety = safe for ANY brand (universal thresholds) - Suitability = safe for MY brand (brand-specific) - Replace three separate prompts with single policy + examples: - Single policy prompt for natural language guidelines - Examples object with acceptable/unacceptable URLs as training set - Update schema and documentation to match 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Fix broken links in content standards docs Remove links to Property Governance and Creative Standards which don't exist in this branch yet. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Align content standards with property protocol patterns Address review comments: 1. Examples now use typed identifiers with language tags: - Uses identifier schema pattern (type: domain, apple_podcast_id, rss_url, etc.) - Added language field (BCP 47 tags like 'en', 'en-US') - Created content-example.json schema 2. Scope fields aligned with property protocol: - brands → brand_ids (references Brand Manifest identifiers) - countries → countries_all (must apply in ALL listed countries) - channels → channels_any (applies to ANY listed channel) - Removed products field (unclear purpose) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Clarify buyer-managed scope selection model The buyer selects the appropriate standards_id when creating a media buy. The seller receives a reference to resolved standards - they don't need to do scope matching themselves. Scope fields are metadata for the buyer's internal organization, not for seller-side resolution. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Address review comments on content standards 1. Scope is targeting, not metadata: - Clarified scope defines where standards apply - Removed "metadata" language 2. Add CRUD tasks for standards management: - Added list_content_standards, create_content_standards, update_content_standards, delete_content_standards - Organized tasks into Discovery, Management, Evaluation sections - Created task documentation pages 3. Clarify evaluation results pattern: - Always returns pass/fail verdict first - Features array is optional breakdown for debugging - Explains use cases: optimization, safety vs suitability, debugging third-party standards (GARM, Scope3) - Updated check-content-response and validate-content-delivery-response schemas to use verdict + optional features pattern 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Refine content standards schema and examples Address review comments: 1. Rename 'examples' to 'calibration': - Better describes the purpose (training/test set for AI interpretation) - Add support for text snippets, image/video/audio URLs 2. Create unified content-context.json schema: - Used for both calibration examples and check_content requests - Supports: domain, text, image_url, video_url, audio_url, rss_url, apple_podcast_id, spotify_show_id, podcast_guid - Optional metadata: language, title, description, categories, text_content 3. Flatten scope structure: - Move brand_ids, countries_all, channels_any to top level - Aligns with property protocol pattern 4. Remove fixed response time claims: - check_content may be async with webhook callback - Let implementations define their own SLAs 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Integrate robust content-context schema from sit/adcp Integrates comprehensive content-context schema improvements: 1. Signals array (replaces simple categories): - Structured signals with key, value, confidence - Supports version, source, and reasons - Examples: iab_category, violence_score, mpaa_rating 2. Structured text_content (replaces simple string): - Array of typed blocks: paragraph, heading, image, video, audio - Images include alt_text, caption, dimensions, type - Video/audio include duration, transcript, transcript_source 3. Rich metadata object: - Open Graph, Twitter Card, JSON-LD - Author, canonical URL, meta tags 4. Temporal fields: - published_time, last_update_time (ISO 8601) 5. artifact_id for cross-reference tracking 6. additionalProperties: true for extensibility Credit: https://github.com/sit/adcp/commit/ca367da 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Update changeset to list all 8 tasks 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Rename check_content to calibrate_content for collaborative calibration - Rename task to emphasize dialogue-based alignment vs runtime evaluation - Add context_id and feedback parameters for multi-turn conversations - Include verbose explanations with confidence scores and policy alignment - Add workflow diagram showing Setup → Activation → Runtime phases - Update schemas with calibrate-content-request/response - Remove old check-content schemas - Update related task links across all task docs Key insight: calibrate_content is low-volume, verbose, dialogue-based; runtime decisioning happens locally at seller for scale. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Use protocol-level context for calibration dialogue Remove context_id and feedback from calibrate_content task - dialogue is handled at the protocol layer via A2A contextId or MCP context_id. Updated documentation to show how multi-turn calibration conversations work using the existing protocol mechanisms for conversation management. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Rename content-context to content with assets array Addresses feedback: 1. Rename "content-context" to "content" - too many "context" terms 2. Restructure to use assets array pattern like creative assets Content is now represented as a collection of assets (text, images, video, audio) plus metadata and signals. This aligns with the creative asset model and avoids overloading "context" terminology. Key changes: - content.json replaces content-context.json - assets array with typed blocks (text, image, video, audio) - identifiers object for platform-specific IDs (apple_podcast_id, etc.) - url is now the primary required field - Updated all docs and schema references 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Rename content to artifact with property_id + artifact_id Content adjacent to ads is now modeled as an "artifact" - identified by property_id (using existing identifier types) plus artifact_id (string defined by property owner). This avoids overloading "content" and enables identification of artifacts that don't have URLs (Instagram, podcasts, TV scenes). Changes: - Rename content.json to artifact.json with new required fields - property_id uses existing identifier type schema (type + value) - artifact_id is a string - property owner defines the scheme - format_id optional - can reference format registry (like creative formats) - url now optional since not all artifacts have URLs - Update all schema references and documentation examples 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Remove signals field, add secured asset access Address review feedback: 1. Remove signals from artifact schema and examples - the verification agent evaluates content directly without pre-computed classifications. This simplifies the model: send content, get responses. 2. Add secured URL access pattern for private assets - supports bearer tokens, service accounts, and pre-signed URLs for content that isn't publicly accessible (AI-generated images, private conversations, paywalled content). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Add artifacts page, restructure overview with strategic framework Restructure Content Standards docs around the key strategic questions: 1. What content? → New artifacts.mdx page with full schema details 2. How much adjacency? → Define in products, negotiate in media buys 3. What sampling rate? → Negotiate coverage vs cost tradeoffs 4. How to calibrate? → Dialogue-based alignment process Changes: - Add standalone artifacts.mdx with asset types and secured access - Replace ASCII workflow with mermaid sequence diagram - Add adjacency and sampling_rate sections to overview - Simplify policy examples (remove verbose calibration details) - Move secured URL access documentation to artifacts page 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Simplify artifact schema: assets required, title as asset, add variant_id - Make assets array required (artifacts without content are meaningless) - Remove title, language, description top-level fields (they're text assets) - Add variant_id for A/B tests, translations, and temporal versions - Add language field to text assets for mixed-language content - Update all documentation examples to use new pattern - Fix schema validation test to handle internal $defs references 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Address review comments on content standards overview - Rename content_standards to content_standards_adjacency_definition - Add Adjacency Units table defining: posts, scenes, segments, seconds, viewports, articles - Clarify human-in-the-loop aspect of calibration process 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Simplify calibrate_content response schema and examples Address review comments: - Remove suggestion field from features (not appropriate for calibration) - Remove policy_alignment (redundant with features breakdown) - Make confidence explicitly optional in docs - Simplify A2A examples to use data-only parts (no text when calling skill) - Update response field table to show required vs optional 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Clarify validate_content_delivery data flow: buyer as intermediary Address review comment about who calls validate_content_delivery: - Delivery records flow from seller → buyer → verification agent - Buyer aggregates delivery data and knows which standards_id applies - Verification agent works on behalf of the buyer Changes: - Add Data Flow section with mermaid diagram to validate_content_delivery.mdx - Add media_buy_id field to request schema and delivery records - Update overview mermaid diagram to show correct flow - Remove suggestion field from response examples 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Add get_media_buy_artifacts task for separate content retrieval Content artifacts (text, images, video) are separate from delivery metrics. This new task allows buyers to request content samples from sellers for validation, keeping the data flow clean: - Buyer calls get_media_buy_artifacts to get content samples - Buyer validates samples with verification agent - Delivery metrics stay in get_media_buy_delivery Updates validate_content_delivery flow to reference new task. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Address review comments on validate_content_delivery schema 1. Remove redundant top-level media_buy_id - keep at record level since records can come from multiple media buys 2. Add country and channel fields to delivery records for targeting context validation 3. Replace creative_id with brand_context placeholder object - the governance agent needs brand/SKU info, not opaque creative IDs. Schema marked as TBD pending brand identifier standardization. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Address PR review comments on Content Standards Protocol - #1/#16: Update artifact description to "content context where placements occur" - #2: Add STANDARDS_IN_USE error code to delete_content_standards - #4: Clarify effective_date semantics (null = not yet effective, multiple allowed) - #5: Add note about calibration data size concerns - #7: Document scope conflict handling in create_content_standards - #8/#9: Rename examples to calibration for consistency - #10: Increase validate_content_delivery response time to 60s - #11: Clarify artifact_id is opaque/flexible - #12/#13: Add notes about auth mechanism extraction for large artifacts - #14/#15: Add effective_date filter and abbreviated response note to list 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Add Content Standards implementation guide Documents implementation patterns for three roles: - Sales agents: accepting standards, calibration, validation - Buyer agents: proxy pattern, orchestrating across publishers - Web publishers: URL-based content with scraper/cache patterns Also documents the content_access pattern for authenticated URL namespace access. Co-Authored-By: Claude Opus 4.5 * Fix implementation guide flow for list_content_features Clarifies that: - Buyers call list_content_features to discover publisher capabilities BEFORE creating standards - Sellers don't need to call back - the standards document contains all required features/rules - Updated step numbering for buyer agent section Co-Authored-By: Claude Opus 4.5 * Remove list_content_features - simplify to accept-or-reject model Content Standards Protocol should be binary: sellers either accept the standards they can fulfill or reject what they cannot. Feature discovery adds unnecessary complexity when we don't yet know how adjacency will play out across different publishers. - Remove list_content_features task and schemas - Simplify implementation guide to focus on accept-or-reject model - Update navigation and schema index Co-Authored-By: Claude Opus 4.5 * Fix calibration and validation flows in implementation guide - Calibration: Seller sends samples TO buyer's governance agent (not reverse) - Validation: Governance agent implements validate_content_delivery (not seller) - Seller's job: Implement get_media_buy_artifacts and support webhooks - Added artifact webhook and reporting webhook requirements for sellers Co-Authored-By: Claude Opus 4.5 * Add artifact webhook spec and clarify role terminology Artifact Webhooks: - Add artifact_webhook config to create-media-buy-request.json - Add artifact-webhook-payload.json schema for push notifications - Supports realtime and batched delivery modes with sampling Role Terminology: - Orchestrator (not "buyer agent") - DSP, trading desk, agency platform - Sales Agent - publisher ad server, SSP - Governance Agent - IAS, DoubleVerify, brand safety service Implementation Guide: - Clear roles table showing who does what - Correct flow: brand → orchestrator → governance agent (setup) → sales agent - Sales agent calibrates against governance agent, not orchestrator - Sales agent pushes artifacts to orchestrator, orchestrator forwards to governance agent Co-Authored-By: Claude Opus 4.5 * Fix terminology: artifacts can be push or pull Changed "push artifacts" to "provide artifacts" since sales agents can either push via artifact_webhook or respond to get_media_buy_artifacts (pull). Co-Authored-By: Claude Opus 4.5 * Simplify content standards: async validation, rename fields, remove competitive separation 1. validate_content_delivery is now async - Accept batch immediately, process in background - Returns validation_id for status polling 2. Rename calibration → calibration_exemplars - More descriptive name for training set - Change acceptable/unacceptable → pass/fail for consistency 3. Remove competitive_separation - Out of scope for content standards - Competitive separation is about ad co-occurrence, not content adjacency - Requires knowledge of other ads on page, which content standards doesn't have Co-Authored-By: Claude Opus 4.5 * Extract content-standards.json and add lifecycle dates 1. Extract reusable content-standards.json schema - Defines brand safety/suitability policies - Can be referenced by get/list/create responses - Includes scope, policy, calibration_exemplars, floor 2. Add termination_date for lifecycle management - effective_date: when standard becomes active (null = draft) - termination_date: when standard was archived (null = active) - Lifecycle states: Draft → Active → Terminated 3. Document lifecycle states in get_content_standards docs - Explains how to identify unused standards for cleanup Co-Authored-By: Claude Opus 4.5 * Add list_content_standards schemas using reusable content-standards.json - list-content-standards-request.json: filters by brand, channel, country - list-content-standards-response.json: returns array of content standards - Response references content-standards.json via $ref, demonstrating reuse - Supports include_terminated and include_drafts filters for lifecycle queries Co-Authored-By: Claude Opus 4.5 * Add effective_date filters and document Content Standards errors - Add effective_before/effective_after filters to list-content-standards-request schema - Add include_terminated/include_drafts to list_content_standards docs - Add schema reference links to list_content_standards docs - Document Content Standards error codes (STANDARDS_NOT_FOUND, STANDARDS_IN_USE, STANDARDS_SCOPE_CONFLICT) Co-Authored-By: Claude Opus 4.5 * Remove lifecycle complexity from Content Standards Simplify by removing effective_date/termination_date lifecycle management: - These are implementation details, not protocol concerns - Governance agent returns current active standards via get_content_standards - Cache-Control headers handle freshness, not effective_date filtering Removed: - effective_date, termination_date from content-standards.json schema - effective_before, effective_after, include_terminated, include_drafts filters - Lifecycle states documentation The protocol should be simple: request standards, get current standards. Co-Authored-By: Claude Opus 4.5 * Refine Content Standards: URI-based floors and validation thresholds - Change floor from enum to URI-based reference (GARM is defunct) - floor now has url, name, and version fields - Supports external floor definitions (e.g., Scope3 brand safety) - Fix calibration_exemplars terminology (pass/fail, not acceptable/unacceptable) - Add validation threshold concept to product catalog - Sellers advertise their calibration accuracy (e.g., 95% aligned) - Acts as contractual guarantee for brand safety compliance Co-Authored-By: Claude Opus 4.5 * Strengthen Content Standards privacy-preserving value proposition - Make clear this is the ONLY solution for ephemeral/sensitive content - Add "using agents to protect privacy" framing - Clarify where each phase runs (calibration, local execution, validation) - Add table showing phase locations and what happens - Add "Future: Secure Enclaves" section with TEE/containerized governance vision - Reference IAB Tech Lab Authentic framework for real-time verification The key insight: the execution engine runs entirely inside the publisher's infrastructure - content never leaves. OpenAI conversations stay within their firewall. This is the fundamental value proposition for AI-generated and privacy-regulated content. Co-Authored-By: Claude Opus 4.5 * Fix IAB Tech Lab reference to ARTF (Agentic RTB Framework) Update the future vision section to reference the correct IAB Tech Lab specification - ARTF defines how service providers package containers deployed into host infrastructure, which is exactly the model Content Standards uses for privacy-preserving brand safety. Co-Authored-By: Claude Opus 4.5 * Add pinhole interface specification for secure enclaves The containerized governance agent needs a well-defined narrow interface: Inbound (verification service → enclave): - Updated models - Policy changes and calibration exemplars - Configuration updates Outbound (enclave → verification service): - Aggregated results (pass rates, drift metrics) - Statistical summaries - Attestation proofs Never crosses the boundary: - Raw content artifacts - User data / PII - Individual impressions This pinhole is the interface that needs standardization for the reference implementation. Co-Authored-By: Claude Opus 4.5 * Replace ASCII art with mermaid diagram for secure enclaves ASCII art doesn't render reliably across different fonts and screen sizes. Mermaid diagrams are supported by Mintlify and render consistently. Co-Authored-By: Claude Opus 4.5 --------- Co-authored-by: Claude Opus 4.5 --- .changeset/content-standards-protocol.md | 19 + docs.json | 21 + .../content-standards/artifacts.mdx | 304 ++++++++++++++ .../implementation-guide.mdx | 389 ++++++++++++++++++ docs/governance/content-standards/index.mdx | 359 ++++++++++++++++ .../tasks/calibrate_content.mdx | 228 ++++++++++ .../tasks/create_content_standards.mdx | 100 +++++ .../tasks/delete_content_standards.mdx | 70 ++++ .../tasks/get_content_standards.mdx | 82 ++++ .../tasks/get_media_buy_artifacts.mdx | 205 +++++++++ .../tasks/list_content_standards.mdx | 69 ++++ .../tasks/update_content_standards.mdx | 70 ++++ .../tasks/validate_content_delivery.mdx | 183 ++++++++ docs/reference/error-codes.mdx | 60 ++- .../artifact-webhook-payload.json | 72 ++++ .../source/content-standards/artifact.json | 309 ++++++++++++++ .../calibrate-content-request.json | 18 + .../calibrate-content-response.json | 73 ++++ .../content-standards/content-standards.json | 80 ++++ .../get-content-standards-request.json | 20 + .../get-content-standards-response.json | 46 +++ .../get-media-buy-artifacts-request.json | 69 ++++ .../get-media-buy-artifacts-response.json | 142 +++++++ .../list-content-standards-request.json | 31 ++ .../list-content-standards-response.json | 52 +++ .../validate-content-delivery-request.json | 80 ++++ .../validate-content-delivery-response.json | 97 +++++ static/schemas/source/index.json | 64 ++- .../media-buy/create-media-buy-request.json | 70 ++++ tests/schema-validation.test.cjs | 19 +- 30 files changed, 3392 insertions(+), 9 deletions(-) create mode 100644 .changeset/content-standards-protocol.md create mode 100644 docs/governance/content-standards/artifacts.mdx create mode 100644 docs/governance/content-standards/implementation-guide.mdx create mode 100644 docs/governance/content-standards/index.mdx create mode 100644 docs/governance/content-standards/tasks/calibrate_content.mdx create mode 100644 docs/governance/content-standards/tasks/create_content_standards.mdx create mode 100644 docs/governance/content-standards/tasks/delete_content_standards.mdx create mode 100644 docs/governance/content-standards/tasks/get_content_standards.mdx create mode 100644 docs/governance/content-standards/tasks/get_media_buy_artifacts.mdx create mode 100644 docs/governance/content-standards/tasks/list_content_standards.mdx create mode 100644 docs/governance/content-standards/tasks/update_content_standards.mdx create mode 100644 docs/governance/content-standards/tasks/validate_content_delivery.mdx create mode 100644 static/schemas/source/content-standards/artifact-webhook-payload.json create mode 100644 static/schemas/source/content-standards/artifact.json create mode 100644 static/schemas/source/content-standards/calibrate-content-request.json create mode 100644 static/schemas/source/content-standards/calibrate-content-response.json create mode 100644 static/schemas/source/content-standards/content-standards.json create mode 100644 static/schemas/source/content-standards/get-content-standards-request.json create mode 100644 static/schemas/source/content-standards/get-content-standards-response.json create mode 100644 static/schemas/source/content-standards/get-media-buy-artifacts-request.json create mode 100644 static/schemas/source/content-standards/get-media-buy-artifacts-response.json create mode 100644 static/schemas/source/content-standards/list-content-standards-request.json create mode 100644 static/schemas/source/content-standards/list-content-standards-response.json create mode 100644 static/schemas/source/content-standards/validate-content-delivery-request.json create mode 100644 static/schemas/source/content-standards/validate-content-delivery-response.json diff --git a/.changeset/content-standards-protocol.md b/.changeset/content-standards-protocol.md new file mode 100644 index 0000000000..2109a9108c --- /dev/null +++ b/.changeset/content-standards-protocol.md @@ -0,0 +1,19 @@ +--- +"adcontextprotocol": minor +--- + +Add Content Standards Protocol for content safety and suitability evaluation. + +Discovery tasks: +- `list_content_features`: Discover available content safety features +- `list_content_standards`: List available standards configurations +- `get_content_standards`: Retrieve content safety policies + +Management tasks: +- `create_content_standards`: Create a new standards configuration +- `update_content_standards`: Update an existing configuration +- `delete_content_standards`: Delete a configuration + +Calibration & Validation tasks: +- `calibrate_content`: Collaborative dialogue to align on policy interpretation +- `validate_content_delivery`: Batch validate delivery records diff --git a/docs.json b/docs.json index 2b008cb872..ab5bb3101e 100644 --- a/docs.json +++ b/docs.json @@ -121,6 +121,27 @@ "pages": [ "docs/governance/brand-standards/index" ] + }, + { + "group": "Content Standards", + "pages": [ + "docs/governance/content-standards/index", + "docs/governance/content-standards/artifacts", + "docs/governance/content-standards/implementation-guide", + { + "group": "Tasks", + "pages": [ + "docs/governance/content-standards/tasks/list_content_standards", + "docs/governance/content-standards/tasks/get_content_standards", + "docs/governance/content-standards/tasks/create_content_standards", + "docs/governance/content-standards/tasks/update_content_standards", + "docs/governance/content-standards/tasks/delete_content_standards", + "docs/governance/content-standards/tasks/calibrate_content", + "docs/governance/content-standards/tasks/get_media_buy_artifacts", + "docs/governance/content-standards/tasks/validate_content_delivery" + ] + } + ] } ] }, diff --git a/docs/governance/content-standards/artifacts.mdx b/docs/governance/content-standards/artifacts.mdx new file mode 100644 index 0000000000..7d2f834a2a --- /dev/null +++ b/docs/governance/content-standards/artifacts.mdx @@ -0,0 +1,304 @@ +--- +title: Artifacts +sidebar_position: 2 +--- + +# Artifacts + +An **artifact** is a unit of content adjacent to an ad placement. When evaluating brand safety and suitability, you're asking: "Is this artifact appropriate for my brand's ads?" + +## What Is an Artifact? + +Artifacts represent the content context where an ad appears: + +- A **news article** on a website +- A **podcast segment** between ad breaks +- A **video chapter** in a YouTube video +- A **social media post** in a feed +- A **scene** in a CTV show +- An **AI-generated image** in a chat conversation + +Artifacts are identified by `property_id` + `artifact_id` - the property defines where the content lives, and the artifact_id is an opaque identifier for that specific piece of content. The artifact_id scheme is flexible - it could be a URL path, a platform-specific ID, or any consistent identifier the property owner uses internally. + +## Structure + +**Schema**: [artifact.json](https://adcontextprotocol.org/schemas/v2/content-standards/artifact.json) + +```json +{ + "property_id": {"type": "domain", "value": "reddit.com"}, + "artifact_id": "r_fitness_post_abc123", + "assets": [ + {"type": "text", "role": "title", "content": "Best protein sources for muscle building", "language": "en"}, + {"type": "text", "role": "paragraph", "content": "Looking for recommendations on high-quality protein sources...", "language": "en"}, + {"type": "image", "url": "https://cdn.reddit.com/fitness-image.jpg", "alt_text": "Person lifting weights"} + ] +} +``` + +### Required Fields + +| Field | Description | +|-------|-------------| +| `property_id` | Where this artifact lives - uses standard identifier types (`domain`, `app_id`, `apple_podcast_id`, etc.) | +| `artifact_id` | Unique identifier within the property - the property owner defines their scheme | +| `assets` | Content in document order - text blocks, images, video, audio | + +### Optional Fields + +| Field | Description | +|-------|-------------| +| `variant_id` | Identifies a specific variant (A/B test, translation, temporal version) | +| `format_id` | Reference to format registry (same as creative formats) | +| `url` | Web URL if the artifact has one | +| `metadata` | Artifact-level metadata (Open Graph, JSON-LD, author info) | +| `published_time` | When the artifact was published | +| `last_update_time` | When the artifact was last modified | + +## Variants + +The same artifact may have multiple variants: + +- **Translations** - English version vs Spanish version +- **A/B tests** - Different headlines being tested +- **Temporal versions** - Content that changed on Wednesday + +Use `variant_id` to distinguish between them: + +```json +// English version +{ + "property_id": {"type": "domain", "value": "nytimes.com"}, + "artifact_id": "article_12345", + "variant_id": "en", + "assets": [ + {"type": "text", "role": "title", "content": "Breaking News Story", "language": "en"} + ] +} + +// Spanish translation +{ + "property_id": {"type": "domain", "value": "nytimes.com"}, + "artifact_id": "article_12345", + "variant_id": "es", + "assets": [ + {"type": "text", "role": "title", "content": "Noticia de última hora", "language": "es"} + ] +} + +// A/B test variant +{ + "property_id": {"type": "domain", "value": "nytimes.com"}, + "artifact_id": "article_12345", + "variant_id": "headline_test_b", + "assets": [ + {"type": "text", "role": "title", "content": "Alternative Headline Being Tested", "language": "en"} + ] +} +``` + +The combination of `artifact_id` + `variant_id` must be unique within a property. This lets you track which variant a user saw and correlate it with delivery reports. + +## Asset Types + +Assets are the actual content within an artifact. Everything is an asset - titles, paragraphs, images, videos. + +### Text + +```json +{"type": "text", "role": "title", "content": "Article Title", "language": "en"} +{"type": "text", "role": "paragraph", "content": "The article body text...", "language": "en"} +{"type": "text", "role": "description", "content": "A summary of the article", "language": "en"} +{"type": "text", "role": "heading", "content": "Section Header", "heading_level": 2} +{"type": "text", "role": "quote", "content": "A quoted statement"} +``` + +Roles: `title`, `description`, `paragraph`, `heading`, `caption`, `quote`, `list_item` + +Each text asset can have its own `language` tag for mixed-language content. + +### Image + +```json +{ + "type": "image", + "url": "https://cdn.example.com/photo.jpg", + "alt_text": "Description of the image" +} +``` + +### Video + +```json +{ + "type": "video", + "url": "https://cdn.example.com/video.mp4", + "transcript": "Full transcript of the video content...", + "duration_ms": 180000 +} +``` + +### Audio + +```json +{ + "type": "audio", + "url": "https://cdn.example.com/podcast.mp3", + "transcript": "Today we're discussing...", + "duration_ms": 3600000 +} +``` + +## Metadata + +Artifact-level metadata describes the artifact as a whole, not individual assets: + +```json +{ + "metadata": { + "author": "Jane Smith", + "canonical": "https://example.com/article/12345", + "open_graph": { + "og:type": "article", + "og:site_name": "Example News" + }, + "json_ld": [ + { + "@type": "NewsArticle", + "datePublished": "2025-01-15" + } + ] + } +} +``` + +This is separate from assets because it's about the artifact container, not the content itself. + +## Secured Asset Access + +Many assets aren't publicly accessible - AI-generated images, private conversations, paywalled content. The artifact schema supports authenticated access. + +### Pre-Configuration (Recommended) + +For ongoing partnerships, configure access once during onboarding rather than per-request: + +1. **Service account sharing** - Grant the verification agent access to your cloud storage +2. **OAuth client credentials** - Set up machine-to-machine authentication +3. **API key exchange** - Share long-lived API keys during setup + +This happens during the activation phase when the seller first receives content standards from a buyer. + +### Per-Asset Authentication + +When pre-configuration isn't possible, include access credentials with individual assets: + +```json +{ + "type": "image", + "url": "https://cdn.openai.com/secured/img_abc123.png", + "access": { + "method": "bearer_token", + "token": "eyJhbGciOiJIUzI1NiIs..." + } +} +``` + +**Note on token size**: For artifacts with many assets, per-asset tokens can significantly increase payload size. Consider: + +1. **Pre-configured access** - Set up service account access once during onboarding +2. **Shared token reference** - Define tokens at the artifact level and reference by ID +3. **Signed URLs** - Use pre-signed URLs where the URL itself is the credential + +The `url` field is the access URL - it may differ from the artifact's canonical/published URL. For example, a published article at `https://news.example.com/article/123` might have assets served from `https://cdn.example.com/secured/...`. + +### Access Methods + +| Method | Use Case | +|--------|----------| +| `bearer_token` | OAuth2 bearer token in Authorization header | +| `service_account` | GCP/AWS service account credentials | +| `signed_url` | Pre-signed URL with embedded credentials (URL itself is the credential) | + +### Service Account Setup + +For GCP: + +```json +{ + "access": { + "method": "service_account", + "provider": "gcp", + "credentials": { + "type": "service_account", + "project_id": "my-project", + "private_key_id": "...", + "private_key": "-----BEGIN PRIVATE KEY-----\n...", + "client_email": "verification-agent@my-project.iam.gserviceaccount.com" + } + } +} +``` + +For AWS: + +```json +{ + "access": { + "method": "service_account", + "provider": "aws", + "credentials": { + "access_key_id": "AKIAIOSFODNN7EXAMPLE", + "secret_access_key": "...", + "region": "us-east-1" + } + } +} +``` + +### Pre-Signed URLs + +For one-off access without sharing credentials: + +```json +{ + "type": "video", + "url": "https://storage.googleapis.com/bucket/video.mp4?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=...&X-Goog-Signature=...", + "access": { + "method": "signed_url" + } +} +``` + +The URL itself contains the credentials - no additional authentication needed. + +## Property Identifier Types + +The `property_id` uses standard identifier types from the AdCP property schema: + +| Type | Example | Use Case | +|------|---------|----------| +| `domain` | `reddit.com` | Websites | +| `app_id` | `com.spotify.music` | Mobile apps | +| `apple_podcast_id` | `1234567890` | Apple Podcasts | +| `spotify_show_id` | `4rOoJ6Egrf8K2IrywzwOMk` | Spotify podcasts | +| `youtube_channel_id` | `UCddiUEpeqJcYeBxX1IVBKvQ` | YouTube channels | +| `rss_url` | `https://feeds.example.com/podcast.xml` | RSS feeds | + +## Artifact ID Schemes + +The property owner defines their artifact_id scheme. Examples: + +| Property Type | Artifact ID Pattern | Example | +|---------------|---------------------|---------| +| News website | `article_{id}` | `article_12345` | +| Reddit | `r_{subreddit}_{post_id}` | `r_fitness_abc123` | +| Podcast | `episode_{num}_segment_{num}` | `episode_42_segment_2` | +| CTV | `show_{id}_s{season}e{episode}_scene_{num}` | `show_abc_s3e5_scene_12` | +| Social feed | `post_{id}` | `post_xyz789` | + +The verification agent doesn't need to understand the scheme - it's opaque. The property owner uses it to correlate artifacts with their content. + +## Related + +- [Content Standards Overview](/docs/governance/content-standards) - How artifacts fit into the content standards workflow +- [calibrate_content](/docs/governance/content-standards/tasks/calibrate_content) - Sending artifacts for calibration diff --git a/docs/governance/content-standards/implementation-guide.mdx b/docs/governance/content-standards/implementation-guide.mdx new file mode 100644 index 0000000000..18a22e0db6 --- /dev/null +++ b/docs/governance/content-standards/implementation-guide.mdx @@ -0,0 +1,389 @@ +--- +title: Implementation Guide +description: How to implement the Content Standards Protocol as a sales agent, orchestrator, or governance agent +--- + +This guide covers implementation patterns for the Content Standards Protocol from three perspectives: + +1. **Sales agents** accepting and enforcing brand safety standards +2. **Orchestrators** coordinating content standards across publishers +3. **Governance agents** providing content evaluation services + +## Roles Overview + +Before diving in, understand who does what: + +| Role | Examples | Responsibilities | +|------|----------|-----------------| +| **Orchestrator** | DSP, trading desk, agency platform | Coordinates media buying; passes standards refs to sellers; receives artifacts for validation | +| **Sales Agent** | Publisher ad server, SSP | Accepts standards; calibrates local model; enforces during delivery; pushes artifacts | +| **Governance Agent** | IAS, DoubleVerify, brand safety service | Hosts standards; implements `calibrate_content` and `validate_content_delivery` | + +The typical flow: + +``` +1. Brand sets up standards with governance agent (via orchestrator) +2. Orchestrator sends standards_ref with get_products/create_media_buy +3. Sales agent accepts or rejects based on capability +4. Sales agent calibrates against governance agent +5. Sales agent enforces during delivery +6. Sales agent provides artifacts (push via webhook or pull via get_media_buy_artifacts) +7. Orchestrator forwards artifacts to governance agent for validation +``` + +--- + +## For Sales Agents + +If you're a sales agent (publisher ad server, SSP, or platform), implementing Content Standards means accepting orchestrator policies and enforcing them during delivery. + +### The Core Model + +When an orchestrator includes a `content_standards_ref` in their request, you must: + +1. **Fetch the standards** from the governance agent and evaluate if you can fulfill them +2. **Accept or reject** the buy based on your capabilities +3. **Calibrate** your evaluation model against the governance agent's expectations +4. **Enforce** the standards during delivery +5. **Provide artifacts** to the orchestrator for validation + +If you cannot fulfill the content standards requirements, **reject the buy**. Don't accept a campaign you can't properly enforce. + +### What You Need to Implement + +**1. Accept content standards references on `get_products` and `create_media_buy`** + +Orchestrators pass their standards via reference: + +```json +{ + "content_standards_ref": { + "standards_id": "nike_emea_brand_safety", + "agent_url": "https://brandsafety.ias.com" + } +} +``` + +When you receive this: +- Fetch the standards document from the governance agent at `agent_url` +- Evaluate whether you can enforce these requirements +- If you cannot meet the standards, reject the request +- If you can, accept and store the association with the media buy + +**2. Decide: Can you fulfill this?** + +The standards document contains: +- Policy (natural language description of acceptable/unacceptable content) +- Calibration exemplars (pass/fail examples to interpret edge cases) +- Floor (reference to external baseline safety standards) + +Review these requirements against your capabilities. Different publishers have different definitions of "adjacency" - Reddit might include comments, YouTube might include related videos, a news site might mean the article body. That's fine - as long as you can meaningfully enforce the brand's intent, accept the buy. + +If you can't - for example, they need adjacency data for a channel where it doesn't apply (like billboards) - reject the buy. + +**3. Build your evaluation capability** + +Use the standards document to train or configure your content evaluation system. This could be: +- An LLM with the rules as system prompt +- A classifier trained on the calibration examples +- A rules engine for deterministic evaluation +- A third-party brand safety vendor + +The protocol doesn't prescribe your implementation - just that you honor the standards. + +**4. Calibrate against the governance agent** + +After accepting the buy, calibrate your local model by calling `calibrate_content` on the governance agent. You send sample artifacts from your inventory, they tell you how they would rate them: + +```json +// You send examples from your inventory to the governance agent +{ + "standards_id": "nike_emea_brand_safety", + "artifacts": [ + { + "property_id": { "type": "domain", "value": "espn.com" }, + "artifact_id": "article_123", + "assets": [{ "type": "text", "role": "title", "content": "Marathon Runner Collapses at Finish Line" }] + } + ] +} + +// Governance agent responds with their interpretation +{ + "evaluations": [{ + "artifact_id": "article_123", + "suitable": true, + "confidence": 0.9, + "explanation": "Sports injury coverage in athletic context - aligns with brand's sports marketing positioning" + }] +} +``` + +Use these responses to train your local model. If you disagree with a rating, ask follow-up questions to understand the governance agent's reasoning. + +**5. Push artifacts to the orchestrator** + +After delivery, push artifacts to the orchestrator so they can validate against the governance agent. Configure via `artifact_webhook` in the media buy: + +```json +// Artifact webhook payload (you send this to the orchestrator) +{ + "media_buy_id": "mb_nike_reddit_q1", + "batch_id": "batch_20250115_001", + "timestamp": "2025-01-15T11:00:00Z", + "artifacts": [ + { + "artifact": { + "property_id": { "type": "domain", "value": "reddit.com" }, + "artifact_id": "r_fitness_abc123", + "assets": [{ "type": "text", "role": "title", "content": "Best protein sources" }] + }, + "delivered_at": "2025-01-15T10:30:00Z", + "impression_id": "imp_abc123" + } + ] +} +``` + +Also support `get_media_buy_artifacts` for orchestrators who prefer to poll. + +### Implementation Checklist + +- [ ] Parse `content_standards_ref` in `get_products` and `create_media_buy` +- [ ] Fetch and evaluate standards documents from governance agents +- [ ] Reject buys you cannot fulfill - don't accept campaigns you can't enforce +- [ ] Build content evaluation against the standards document +- [ ] Call `calibrate_content` on the governance agent to align interpretation +- [ ] Implement `get_media_buy_artifacts` so orchestrators can retrieve content for validation +- [ ] Support `artifact_webhook` for push-based artifact delivery +- [ ] Support `reporting_webhook` for delivery metrics + +--- + +## For Orchestrators + +If you're an orchestrator (DSP, trading desk, or agency platform), you coordinate content standards between brands, governance agents, and publishers. + +### The Orchestration Pattern + +``` +Brand → Orchestrator → Governance Agent (setup) + → Sales Agent (buying) + ← Sales Agent (artifacts) + → Governance Agent (validation) + → Brand (reporting) +``` + +**1. Help brands set up standards with governance agents** + +Brands create content standards through a governance agent. You might facilitate this or the brand may do it directly: + +```json +// Standards stored at the governance agent +{ + "standards_id": "nike_emea_brand_safety", + "name": "Nike EMEA Brand Safety Policy", + "brand_id": "nike", + "policy": "Sports and fitness content is ideal. Avoid violence, adult themes, drugs.", + "calibration_exemplars": { + "pass": [ + { "type": "domain", "value": "espn.com" } + ], + "fail": [ + { "type": "domain", "value": "tabloid.example.com" } + ] + }, + "floor": { + "url": "https://scope3.com/brand-safety-floor", + "name": "Scope3 Common Sense Brand Safety" + } +} +``` + +**2. Pass standards references when buying** + +When discovering products or creating media buys, include the governance agent reference: + +```json +{ + "product_id": "espn_sports_display", + "packages": [...], + "content_standards_ref": { + "standards_id": "nike_emea_brand_safety", + "agent_url": "https://brandsafety.ias.com" + }, + "artifact_webhook": { + "url": "https://your-platform.com/webhooks/artifacts", + "authentication": { + "schemes": ["HMAC-SHA256"], + "credentials": "your-shared-secret-min-32-chars" + }, + "delivery_mode": "batched", + "batch_frequency": "hourly", + "sampling_rate": 0.25 + } +} +``` + +If the publisher cannot fulfill the standards, they should reject the buy. Handle rejections gracefully and find alternative inventory. + +**3. Receive artifacts from sales agents** + +Sales agents push artifacts to your `artifact_webhook` endpoint. Forward them to the governance agent for validation: + +```python +# Receive artifact webhook from sales agent +@app.post("/webhooks/artifacts") +async def receive_artifacts(payload: ArtifactWebhookPayload): + # Forward to governance agent for validation + validation_result = await governance_agent.validate_content_delivery( + standards_id=get_standards_id(payload.media_buy_id), + records=[ + {"artifact": a.artifact, "record_id": a.impression_id} + for a in payload.artifacts + ] + ) + + # Log any failures + for result in validation_result.results: + if any(f.status == "failed" for f in result.features): + log_brand_safety_incident(payload.media_buy_id, result) + + return {"status": "received", "batch_id": payload.batch_id} +``` + +**4. Report to brands** + +Surface validation results to the brand: +- **Incidents**: Content that didn't meet standards +- **Coverage**: What percentage of delivery was validated +- **Trends**: Changes in content safety over time + +### Implementation Checklist + +- [ ] Facilitate brand setup with governance agents +- [ ] Include `content_standards_ref` in `get_products` and `create_media_buy` requests +- [ ] Configure `artifact_webhook` to receive artifacts from sales agents +- [ ] Handle rejections from publishers who can't fulfill standards +- [ ] Forward artifacts to governance agent via `validate_content_delivery` +- [ ] Build reporting for brands + +--- + +## For Governance Agents + +If you're a governance agent (IAS, DoubleVerify, or brand safety service), you provide content evaluation as a service. + +### What You Implement + +**1. Host and serve content standards** + +Store standards configurations and expose them via `get_content_standards`: + +```json +// Response to get_content_standards +{ + "standards_id": "nike_emea_brand_safety", + "version": "1.2.0", + "name": "Nike EMEA - all digital channels", + "policy": "Sports and fitness content is ideal. Lifestyle content about health is good...", + "calibration_exemplars": { + "pass": [...], + "fail": [...] + }, + "floor": { + "url": "https://scope3.com/brand-safety-floor", + "name": "Scope3 Common Sense Brand Safety" + } +} +``` + +**2. Implement `calibrate_content`** + +Sales agents call this to align their local models before campaign execution. They send sample artifacts, you respond with how the brand would rate them: + +```python +def calibrate_content(standards_id: str, artifacts: list) -> dict: + standards = get_standards(standards_id) + evaluations = [] + + for artifact in artifacts: + # Evaluate against brand's policy + result = evaluate_against_policy(artifact, standards) + evaluations.append({ + "artifact_id": artifact["artifact_id"], + "suitable": result.suitable, + "confidence": result.confidence, + "explanation": result.explanation # Help them understand your reasoning + }) + + return {"evaluations": evaluations} +``` + +Calibration is a dialogue - be prepared for follow-up questions and edge cases. + +**3. Implement `validate_content_delivery`** + +Orchestrators call this to validate artifacts after delivery. Batch evaluation at scale: + +```python +def validate_content_delivery(standards_id: str, records: list) -> dict: + standards = get_standards(standards_id) + results = [] + + for record in records: + features = [] + for feature in ["brand_safety", "brand_suitability"]: + evaluation = evaluate_feature(record["artifact"], standards, feature) + features.append({ + "feature_id": feature, + "status": "passed" if evaluation.passed else "failed", + "value": evaluation.value, + "message": evaluation.message if not evaluation.passed else None + }) + results.append({ + "record_id": record["record_id"], + "features": features + }) + + return { + "summary": compute_summary(results), + "results": results + } +``` + +### Implementation Checklist + +- [ ] Implement `create_content_standards` for brands to set up policies +- [ ] Implement `get_content_standards` for sales agents to fetch policies +- [ ] Implement `calibrate_content` for sales agents to align their models +- [ ] Implement `validate_content_delivery` for orchestrators to validate delivery +- [ ] Support dialogue in calibration (follow-up questions, edge cases) + +--- + +## Content Access Pattern + +All three roles may need to exchange content securely. The `content_access` pattern provides authenticated access to a URL namespace: + +```json +{ + "content_access": { + "url_pattern": "https://cache.example.com/*", + "auth": { + "type": "bearer", + "token": "eyJ..." + } + } +} +``` + +- **url_pattern**: URLs matching this pattern use this auth +- **auth.type**: Authentication method (`bearer`, `api_key`, `signed_url`) +- **auth.token**: The credential + +Include this in: +- `get_content_standards` response (governance agent → sales agent: "fetch examples here") +- `get_media_buy_artifacts` response (sales agent → orchestrator: "fetch content here") + +This avoids per-asset tokens and keeps payloads small while enabling secure content exchange. diff --git a/docs/governance/content-standards/index.mdx b/docs/governance/content-standards/index.mdx new file mode 100644 index 0000000000..5328d7a0f1 --- /dev/null +++ b/docs/governance/content-standards/index.mdx @@ -0,0 +1,359 @@ +--- +title: Overview +sidebar_position: 1 +--- + +# Content Standards Protocol + +The Content Standards Protocol enables **privacy-preserving brand safety** for ephemeral and sensitive content that cannot leave a publisher's infrastructure. + +## The Problem + +Traditional brand safety relies on third-party verification: send your content to IAS or DoubleVerify, they evaluate it, return a verdict. This works for static web pages. It fundamentally cannot work for: + +- **AI-generated content** - ChatGPT responses, DALL-E images that exist only in a user session +- **Private conversations** - Content in messaging apps, private social feeds +- **Ephemeral content** - Stories, live streams, real-time feeds that disappear +- **Privacy-regulated content** - GDPR-protected data that cannot be exported + +For these platforms, **there is no traditional verification option**. The content simply cannot leave. OpenAI cannot send user conversations to an external service. A messaging app cannot export private chats. A streaming platform cannot share real-time content before it disappears. + +Yet these are exactly the environments where advertising is growing fastest - and where brands most need safety guarantees. Without a privacy-preserving approach, brands either avoid these channels entirely or accept unknown risk. + +## The Solution: Calibration-Based Alignment + +Content Standards solves this by **using agents to protect privacy**. It's a three-phase model where no sensitive content ever leaves the publisher's infrastructure: + +| Phase | Where It Runs | What Happens | +|-------|---------------|--------------| +| **1. Calibration** | External (safe data only) | Publisher and verification agent align on policy interpretation using synthetic examples or public samples - no PII, no sensitive content | +| **2. Local Execution** | Inside publisher's walls | Publisher runs evaluation on every impression using a local model trained during calibration - content never leaves | +| **3. Validation** | Statistical sampling | Verification agent audits a sample to detect drift - both parties can verify the system is working without exposing PII | + +This inverts the traditional model. Instead of "send us your content, we'll evaluate it," it's "we'll teach you our standards, you evaluate locally, we'll audit statistically." + +**The key insight**: The execution engine runs entirely inside the publisher's infrastructure. For OpenAI, that means brand safety evaluation happens within their firewall - user conversations never leave. For a messaging app, it means private content stays private. The calibration and validation phases provide confidence that the local model is working correctly, without ever requiring access to sensitive data. + +## What It Covers + +- **Brand safety** - Is this content safe for *any* brand? (universal thresholds like hate speech, illegal content) +- **Brand suitability** - Is this content appropriate for *my* brand? (brand-specific preferences and tone) + +## Key Concepts + +Content standards evaluation involves four key questions that buyers and sellers negotiate: + +1. **What content?** - What [artifacts](/docs/governance/content-standards/artifacts) to evaluate (the ad-adjacent content) +2. **How much adjacency?** - How many artifacts around the ad slot to consider +3. **What sampling rate?** - What percentage of traffic to evaluate +4. **How to calibrate?** - How to align on policy interpretation before runtime + +These parameters are negotiated between buyer and seller during product discovery and media buy creation. + +## Workflow + +```mermaid +sequenceDiagram + participant Brand + participant Buyer as Buyer Agent + participant Seller as Seller Agent + participant Verifier as Verification Agent + + Note over Brand,Verifier: 1. SETUP PHASE + Brand->>Verifier: create_content_standards (policy + calibration examples) + Verifier-->>Brand: standards_id + + Note over Brand,Verifier: 2. ACTIVATION PHASE + Brand->>Buyer: "Buy inventory from Reddit, use standards_id X" + Buyer->>Seller: create_media_buy (includes content_standards reference) + + Seller->>Verifier: calibrate_content (sample artifacts) + Verifier-->>Seller: verdict + explanation + Seller->>Verifier: "What about this edge case?" + Verifier-->>Seller: clarification + Note over Seller: Seller builds local model + + Note over Brand,Verifier: 3. RUNTIME PHASE + loop High-volume decisioning + Note over Seller: Local model evaluates artifacts + end + + Buyer->>Seller: get_media_buy_artifacts (sampled) + Seller-->>Buyer: Content artifacts + Buyer->>Verifier: validate_content_delivery + Verifier-->>Buyer: Validation results +``` + +**Key insight**: Runtime decisioning happens locally at the seller (for scale). Buyers pull content samples from sellers and validate against the verification agent. + +## Adjacency + +How much content around the ad slot should be evaluated? + +| Context | Adjacency Examples | +|---------|-------------------| +| **News article** | The article where the ad appears | +| **Social feed** | 1-2 posts above and below the ad slot | +| **Podcast** | The segment before and after the ad break | +| **CTV** | 1-2 scenes before and after the ad pod | +| **Infinite scroll** | Posts within the visible viewport | + +Adjacency requirements are defined by the seller in their product catalog (`get_products`). The buyer can filter products based on adjacency guarantees: + +```json +{ + "product_id": "reddit_feed_standard", + "content_standards_adjacency_definition": { + "before": 2, + "after": 2, + "unit": "posts" + } +} +``` + +### Adjacency Units + +| Unit | Use Case | +|------|----------| +| `posts` | Social feeds, forums, comment threads | +| `scenes` | CTV, streaming video content | +| `segments` | Podcasts, audio content | +| `seconds` | Time-based adjacency in video/audio | +| `viewports` | Infinite scroll contexts | +| `articles` | News sites, content aggregators | + +Different products may offer different adjacency guarantees at different price points. + +## Sampling Rate + +What percentage of traffic should be evaluated by the verification agent? + +| Rate | Use Case | +|------|----------| +| **100%** | Premium brand safety - every impression validated | +| **10-25%** | Standard monitoring - statistical confidence | +| **1-5%** | Spot checking - drift detection only | + +Sampling rate is negotiated in the media buy: + +```json +{ + "governance": { + "content_standards": { + "agent_url": "https://safety.ias.com/adcp", + "standards_id": "nike_brand_safety", + "sampling_rate": 0.25 + } + } +} +``` + +Higher sampling rates typically cost more but provide stronger guarantees. The seller is responsible for implementing the agreed sampling rate and reporting actual coverage. + +## Validation Thresholds + +When a seller calibrates their local model against a verification agent, there's an expected drift - the local model won't match the verification agent 100% of the time. **Validation thresholds** define acceptable drift between local execution and validation samples. + +Sellers advertise their content safety capabilities in their product catalog: + +```json +{ + "product_id": "reddit_feed_premium", + "content_standards": { + "validation_threshold": 0.95, + "validation_threshold_description": "Local model matches verification agent 95% of the time" + } +} +``` + +| Threshold | Meaning | +|-----------|---------| +| **0.99** | Premium - local model is 99% aligned with verification agent | +| **0.95** | Standard - local model is 95% aligned | +| **0.90** | Budget - local model is 90% aligned | + +**This is a contractual guarantee.** If the seller's validation results show more drift than the advertised threshold, buyers can expect remediation (makegoods, refunds, etc.) just like any other delivery discrepancy. + +The threshold answers the key buyer question: "If I accept your local model, how confident can I be that you're enforcing my standards correctly?" + +## Policies + +Content Standards uses **natural language prompts** rather than rigid keyword lists: + +```json +{ + "policy": "Sports and fitness content is ideal. Lifestyle content about health is good. Entertainment is generally acceptable. Avoid content about violence, controversial politics, adult themes, or content portraying sedentary lifestyle positively. Block hate speech, illegal activities, or ongoing litigation against our company.", + "calibration_exemplars": { + "pass": [ + { + "property_id": {"type": "domain", "value": "espn.com"}, + "artifact_id": "nba_championship_recap_2024", + "assets": [{"type": "text", "role": "title", "content": "Championship Game Recap"}] + } + ], + "fail": [ + { + "property_id": {"type": "domain", "value": "tabloid.example.com"}, + "artifact_id": "scandal_story_123", + "assets": [{"type": "text", "role": "title", "content": "Celebrity Scandal Exposed"}] + } + ] + } +} +``` + +The policy prompt enables AI-powered verification agents to understand context and nuance. **Calibration** examples provide a training/test set that helps the agent interpret the policy correctly. + +See [Artifacts](/docs/governance/content-standards/artifacts) for details on artifact structure and secured asset access. + +## Scoped Standards + +Buyers typically maintain multiple standards configurations for different contexts - UK TV campaigns have different regulations than US display, and children's brands need stricter safety than adult beverages. + +```json +{ + "standards_id": "coke_uk_tv_zero", + "name": "UK TV - Coca-Cola zero-calorie brands", + "brand_ids": ["coke_zero", "diet_coke"], + "countries_all": ["GB"], + "channels_any": ["ctv", "linear_tv"] +} +``` + +**The buyer selects the appropriate `standards_id` when creating a media buy.** The seller receives a reference to the resolved standards - they don't need to do scope matching themselves. + +## Calibration + +Before running campaigns, sellers calibrate their local models against the verification agent. This is a **dialogue-based process** that may involve human review on either side: + +1. Seller sends sample artifacts to the verification agent +2. Verification agent returns verdicts with detailed explanations +3. Seller asks follow-up questions about edge cases +4. Process repeats until alignment is achieved + +**Human-in-the-loop**: Calibration often involves humans on both sides. A brand safety specialist at the buyer might review edge cases flagged by the verification agent. A content operations team at the seller might curate calibration samples and validate the local model's learning. The protocol supports async workflows where either party can pause for human review before responding. + +```json +// Seller: "Does this pass?" +{ + "artifact": { + "property_id": {"type": "domain", "value": "reddit.com"}, + "artifact_id": "r_news_politics_123", + "assets": [{"type": "text", "role": "title", "content": "Political News Article"}] + } +} + +// Verification agent: "No, because..." +{ + "verdict": "fail", + "explanation": "Political content is excluded by brand policy, even when balanced.", + "policy_alignment": { + "violations": [{ + "policy_text": "Avoid content about controversial politics", + "violation_reason": "Article discusses ongoing political controversy" + }] + } +} +``` + +See [calibrate_content](/docs/governance/content-standards/tasks/calibrate_content) for the full task specification. + +## Tasks + +### Discovery + +| Task | Description | +|------|-------------| +| [list_content_standards](/docs/governance/content-standards/tasks/list_content_standards) | List available standards configurations | +| [get_content_standards](/docs/governance/content-standards/tasks/get_content_standards) | Retrieve a specific standards configuration | + +### Management + +| Task | Description | +|------|-------------| +| [create_content_standards](/docs/governance/content-standards/tasks/create_content_standards) | Create a new standards configuration | +| [update_content_standards](/docs/governance/content-standards/tasks/update_content_standards) | Update an existing standards configuration | +| [delete_content_standards](/docs/governance/content-standards/tasks/delete_content_standards) | Delete a standards configuration | + +### Calibration & Validation + +| Task | Description | +|------|-------------| +| [calibrate_content](/docs/governance/content-standards/tasks/calibrate_content) | Collaborative dialogue to align on policy interpretation | +| [get_media_buy_artifacts](/docs/governance/content-standards/tasks/get_media_buy_artifacts) | Retrieve content artifacts from a media buy | +| [validate_content_delivery](/docs/governance/content-standards/tasks/validate_content_delivery) | Batch validation of content artifacts | + +## Typical Providers + +- **IAS** - Integral Ad Science +- **DoubleVerify** - Brand safety and verification +- **Scope3** - Sustainability-focused brand safety with prompt-based policies +- **Custom** - Brand-specific implementations + +## Future: Secure Enclaves + +The current model trusts the publisher to faithfully implement the calibrated standards. A future evolution uses **secure enclaves** (Trusted Execution Environments / TEEs) to provide cryptographic guarantees: + +```mermaid +flowchart TB + subgraph VS["Verification Service"] + Models["Models & Calibration Data"] + Results["Aggregate Results"] + end + + subgraph PUB["Publisher Infrastructure"] + subgraph TEE["Secure Enclave (TEE)"] + Agent["Containerized
Governance Agent"] + end + Content["Content Artifacts"] + end + + Models -->|"Pinhole IN:
models, policy, examples"| Agent + Agent -->|"Pinhole OUT:
pass rates, drift metrics"| Results + Content -->|"evaluate"| Agent + Agent -->|"pass/fail verdict"| Content + + style TEE fill:#e8f5e9,stroke:#4caf50 + style Agent fill:#c8e6c9,stroke:#388e3c + style PUB fill:#fafafa,stroke:#9e9e9e +``` + +**Content never crosses the pinhole** - only models flow in, only aggregates flow out. + +### The Pinhole Interface + +The enclave maintains a narrow, well-defined interface to the verification service: + +**Inbound (verification service → enclave):** +- Updated brand safety models +- Policy changes and calibration exemplars +- Configuration updates + +**Outbound (enclave → verification service):** +- Aggregated validation results (pass rates, drift metrics) +- Statistical summaries +- Attestation proofs + +**Never crosses the boundary:** +- Raw content artifacts +- User data or PII +- Individual impression-level data + +This pinhole is the interface that needs standardization - it defines exactly what flows in and out while keeping sensitive content locked inside the publisher's walls. + +### Why This Matters + +- **Publisher** hosts a secure enclave inside their infrastructure +- **Governance agent** (from IAS, DoubleVerify, etc.) runs as a container within the enclave +- **Content** flows into the enclave for evaluation but never leaves the publisher's walls +- **Both parties** can verify the governance code is running unmodified via attestation +- **Models stay current** - the enclave can receive updates without exposing content + +This provides the same privacy guarantees as local execution, but with cryptographic proof that the correct algorithm is running. The brand knows their standards are being enforced faithfully. The publisher proves compliance without exposing content. + +This architecture aligns with the [IAB Tech Lab ARTF (Agentic RTB Framework)](https://iabtechlab.com/standards/artf/), which defines how service providers can package offerings as containers deployed into host infrastructure. ARTF enables hosts to "provide greater access to data and more interaction opportunities to service agents without concerns about leakage, misappropriation or latency" - exactly the model Content Standards requires for privacy-preserving brand safety. + +## Related + +- [Artifacts](/docs/governance/content-standards/artifacts) - What artifacts are and how to structure them +- [Brand Manifest](/docs/creative/brand-manifest) - Static brand identity that can link to standards agents diff --git a/docs/governance/content-standards/tasks/calibrate_content.mdx b/docs/governance/content-standards/tasks/calibrate_content.mdx new file mode 100644 index 0000000000..801ee3bb53 --- /dev/null +++ b/docs/governance/content-standards/tasks/calibrate_content.mdx @@ -0,0 +1,228 @@ +--- +title: calibrate_content +sidebar_position: 7 +--- + +# calibrate_content + +Collaborative calibration task for aligning on content standards interpretation. Used during setup to help sellers understand and internalize a buyer's content policies before campaign execution. + +Unlike high-volume runtime evaluation, calibration is a **dialogue-based process** where parties exchange examples and explanations until aligned. + +## When to Use + +- **Seller onboarding**: When a seller first receives content standards from a buyer +- **Policy clarification**: When a seller needs to understand why specific content passes or fails +- **Model training**: When building a local model to run against the standards +- **Drift detection**: Periodic re-calibration to ensure continued alignment + +## Request + +**Schema**: [calibrate-content-request.json](https://adcontextprotocol.org/schemas/v2/content-standards/calibrate-content-request.json) + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `standards_id` | string | Yes | Standards configuration to calibrate against | +| `artifact` | artifact | Yes | Artifact to evaluate | + +### Artifact + +**Schema**: [artifact.json](https://adcontextprotocol.org/schemas/v2/content-standards/artifact.json) + +An artifact represents content context where ad placements occur - identified by `property_id` + `artifact_id` and represented as a collection of assets: + +```json +{ + "property_id": {"type": "domain", "value": "reddit.com"}, + "artifact_id": "r_fitness_abc123", + "assets": [ + {"type": "text", "role": "title", "content": "Best protein sources for muscle building", "language": "en"}, + {"type": "text", "role": "paragraph", "content": "Looking for recommendations on high-quality protein sources...", "language": "en"}, + {"type": "text", "role": "paragraph", "content": "I've been lifting for 6 months and want to optimize my diet.", "language": "en"}, + {"type": "image", "url": "https://cdn.reddit.com/fitness-image.jpg", "alt_text": "Person lifting weights"} + ] +} +``` + +## Response + +**Schema**: [calibrate-content-response.json](https://adcontextprotocol.org/schemas/v2/content-standards/calibrate-content-response.json) + +### Passing Response + +```json +{ + "verdict": "pass", + "explanation": "This content aligns well with the brand's fitness-focused positioning. Health and fitness content is explicitly marked as 'ideal' in the policy. The discussion is constructive and educational.", + "features": [ + { + "feature_id": "brand_safety", + "status": "passed", + "explanation": "No safety concerns. Content is user-generated but constructive fitness discussion." + }, + { + "feature_id": "brand_suitability", + "status": "passed", + "explanation": "Fitness content matches brand's athletic positioning." + } + ] +} +``` + +### Failing Response with Detailed Explanation + +```json +{ + "verdict": "fail", + "explanation": "This content discusses political topics which the policy explicitly excludes. While the article itself is balanced journalism, the brand has requested to avoid all controversial political content regardless of tone.", + "features": [ + { + "feature_id": "brand_safety", + "status": "passed", + "explanation": "No hate speech, illegal content, or explicit material." + }, + { + "feature_id": "brand_suitability", + "status": "failed", + "explanation": "Political content is excluded by brand policy, even when balanced." + } + ] +} +``` + +### Response Fields + +| Field | Required | Description | +|-------|----------|-------------| +| `verdict` | Yes | Overall `pass` or `fail` decision | +| `explanation` | No | Detailed natural language explanation of the decision | +| `features` | No | Per-feature breakdown with explanations | +| `confidence` | No | Model confidence in the verdict (0-1), when available | + +## Dialogue Flow + +Calibration supports back-and-forth dialogue using the protocol's conversation management. The seller sends content, the verification agent responds with an evaluation and explanation, and the seller can respond with questions or try different content - all within the same conversation context. + +### A2A Example + +```javascript +// Seller sends artifact to evaluate +const response1 = await a2a.send({ + message: { + parts: [{ + kind: "data", + data: { + skill: "calibrate_content", + parameters: { + standards_id: "nike_brand_safety", + artifact: { + property_id: { type: "domain", value: "reddit.com" }, + artifact_id: "r_news_politics_123", + assets: [ + { type: "text", role: "title", content: "Political News Article" } + ] + } + } + } + }] + } +}); +// Response: verdict=fail with feature breakdown + +// Seller asks follow-up question about the decision +const response2 = await a2a.send({ + contextId: response1.contextId, + message: { + parts: [{ + kind: "text", + text: "This is factual news, not opinion. Should balanced journalism be excluded?" + }] + } +}); +// Verification agent clarifies that brand policy excludes ALL political content + +// Seller tries different artifact +const response3 = await a2a.send({ + contextId: response1.contextId, + message: { + parts: [{ + kind: "data", + data: { + skill: "calibrate_content", + parameters: { + standards_id: "nike_brand_safety", + artifact: { + property_id: { type: "domain", value: "reddit.com" }, + artifact_id: "r_running_tips_456", + assets: [ + { type: "text", role: "title", content: "Running Tips" } + ] + } + } + } + }] + } +}); +// Response: verdict=pass - now seller understands the boundaries +``` + +### MCP Example + +```javascript +// Initial calibration request +const response1 = await mcp.call('calibrate_content', { + standards_id: "nike_brand_safety", + artifact: { + property_id: { type: "domain", value: "reddit.com" }, + artifact_id: "r_news_politics_123", + assets: [ + { type: "text", role: "title", content: "Political News Article" } + ] + } +}); +// Response includes context_id for conversation continuity + +// Continue dialogue with follow-up question +const response2 = await mcp.call('calibrate_content', { + context_id: response1.context_id, + standards_id: "nike_brand_safety", + artifact: { + property_id: { type: "domain", value: "reddit.com" }, + artifact_id: "r_news_politics_123", + assets: [ + { type: "text", role: "title", content: "Political News Article" } + ] + } +}); +// Include text message in the protocol envelope asking about balanced journalism + +// Try different artifact in same conversation +const response3 = await mcp.call('calibrate_content', { + context_id: response1.context_id, + standards_id: "nike_brand_safety", + artifact: { + property_id: { type: "domain", value: "reddit.com" }, + artifact_id: "r_running_tips_456", + assets: [ + { type: "text", role: "title", content: "Running Tips" } + ] + } +}); +``` + +The key insight is that the dialogue happens at the **protocol layer**, not the task layer. The verification agent maintains conversation context and can respond to follow-up questions, disagreements, or requests for clarification - just like any agent-to-agent conversation. + +## Calibration vs Runtime + +| Aspect | calibrate_content | Runtime (local model) | +|--------|-------------------|----------------------| +| **Purpose** | Alignment & understanding | High-volume decisioning | +| **Volume** | Low (setup/periodic) | High (every impression) | +| **Response** | Verbose explanations | Pass/fail only | +| **Latency** | Seconds acceptable | Milliseconds required | +| **Dialogue** | Multi-turn conversation | Stateless | + +## Related Tasks + +- [get_content_standards](/docs/governance/content-standards/tasks/get_content_standards) - Retrieve the policies being calibrated against +- [validate_content_delivery](/docs/governance/content-standards/tasks/validate_content_delivery) - Post-campaign delivery validation diff --git a/docs/governance/content-standards/tasks/create_content_standards.mdx b/docs/governance/content-standards/tasks/create_content_standards.mdx new file mode 100644 index 0000000000..7c73c577cc --- /dev/null +++ b/docs/governance/content-standards/tasks/create_content_standards.mdx @@ -0,0 +1,100 @@ +--- +title: create_content_standards +sidebar_position: 5 +--- + +# create_content_standards + +Create a new content standards configuration. + +**Response time**: < 1s + +## Request + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `scope` | object | Yes | Where this standards configuration applies | +| `policy` | string | Yes | Natural language policy prompt | +| `calibration_exemplars` | object | No | Training set of pass/fail artifacts for calibration | +| `floor` | object | No | Safety floor baseline - reference to external floor definition | + +### Example Request + +```json +{ + "scope": { + "brand_ids": ["nike"], + "countries_all": ["GB", "DE", "FR"], + "channels_any": ["display", "video", "ctv"], + "description": "Nike EMEA - all digital channels" + }, + "policy": "Sports and fitness content is ideal. Lifestyle content about health and wellness is good. Entertainment content is generally acceptable. Avoid content about violence, controversial political topics, adult themes, or content that portrays sedentary lifestyle positively.", + "calibration_exemplars": { + "pass": [ + { "type": "domain", "value": "espn.com", "language": "en" }, + { "type": "domain", "value": "healthline.com", "language": "en" } + ], + "fail": [ + { "type": "domain", "value": "tabloid.example.com", "language": "en" } + ] + }, + "floor": { + "url": "https://scope3.com/brand-safety-floor", + "name": "Scope3 Common Sense Brand Safety" + } +} +``` + +## Response + +### Success Response + +```json +{ + "standards_id": "nike_emea_safety", + "version": "1.0.0" +} +``` + +### Error Responses + +**Invalid Scope:** + +```json +{ + "errors": [ + { + "code": "INVALID_SCOPE", + "message": "At least one brand_id is required" + } + ] +} +``` + +**Scope Conflict:** + +```json +{ + "errors": [ + { + "code": "SCOPE_CONFLICT", + "message": "Standards already exist for brand 'nike' in country 'DE' on channel 'display'", + "conflicting_standards_id": "nike_emea_safety" + } + ] +} +``` + +## Scope Conflict Handling + +Multiple standards cannot have overlapping scopes for the same brand/country/channel combination. When creating standards that would conflict: + +1. **Check existing standards** - Use [list_content_standards](/docs/governance/content-standards/tasks/list_content_standards) filtered by your scope +2. **Update rather than create** - If standards already exist, use [update_content_standards](/docs/governance/content-standards/tasks/update_content_standards) +3. **Narrow the scope** - Adjust countries or channels to avoid overlap + +## Related Tasks + +- [list_content_standards](/docs/governance/content-standards/tasks/list_content_standards) - List all configurations +- [update_content_standards](/docs/governance/content-standards/tasks/update_content_standards) - Update a configuration +- [delete_content_standards](/docs/governance/content-standards/tasks/delete_content_standards) - Delete a configuration diff --git a/docs/governance/content-standards/tasks/delete_content_standards.mdx b/docs/governance/content-standards/tasks/delete_content_standards.mdx new file mode 100644 index 0000000000..2f38244c51 --- /dev/null +++ b/docs/governance/content-standards/tasks/delete_content_standards.mdx @@ -0,0 +1,70 @@ +--- +title: delete_content_standards +sidebar_position: 7 +--- + +# delete_content_standards + +Delete a content standards configuration. + +**Response time**: < 500ms + +## Request + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `standards_id` | string | Yes | ID of the standards configuration to delete | + +### Example Request + +```json +{ + "standards_id": "nike_emea_safety" +} +``` + +## Response + +### Success Response + +```json +{ + "deleted": true, + "standards_id": "nike_emea_safety" +} +``` + +### Error Responses + +**Not Found:** + +```json +{ + "errors": [ + { + "code": "STANDARDS_NOT_FOUND", + "message": "No standards found with ID 'invalid_id'" + } + ] +} +``` + +**Standards In Use:** + +```json +{ + "errors": [ + { + "code": "STANDARDS_IN_USE", + "message": "Cannot delete standards 'nike_emea_safety' - currently referenced by active media buys" + } + ] +} +``` + +Standards cannot be deleted while they are referenced by active media buys. Use [list_content_standards](/docs/governance/content-standards/tasks/list_content_standards) to identify usage, or archive standards by setting an expiration date rather than deleting. + +## Related Tasks + +- [list_content_standards](/docs/governance/content-standards/tasks/list_content_standards) - List all configurations +- [create_content_standards](/docs/governance/content-standards/tasks/create_content_standards) - Create a new configuration diff --git a/docs/governance/content-standards/tasks/get_content_standards.mdx b/docs/governance/content-standards/tasks/get_content_standards.mdx new file mode 100644 index 0000000000..74229890e4 --- /dev/null +++ b/docs/governance/content-standards/tasks/get_content_standards.mdx @@ -0,0 +1,82 @@ +--- +title: get_content_standards +sidebar_position: 2 +--- + +# get_content_standards + +Retrieve content safety policies for a specific standards configuration. + +## Request + +**Schema**: [get-content-standards-request.json](https://adcontextprotocol.org/schemas/v2/content-standards/get-content-standards-request.json) + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `standards_id` | string | Yes | Identifier for the standards configuration | + +## Response + +**Schema**: [get-content-standards-response.json](https://adcontextprotocol.org/schemas/v2/content-standards/get-content-standards-response.json) + +### Success Response + +```json +{ + "standards_id": "nike_emea_safety", + "version": "1.2.0", + "name": "Nike EMEA - all digital channels", + "brand_ids": ["nike"], + "countries_all": ["GB", "DE", "FR"], + "channels_any": ["display", "video", "ctv"], + "policy": "Sports and fitness content is ideal. Lifestyle content about health and wellness is good. Entertainment content is generally acceptable. Avoid content about violence, controversial political topics, adult themes, or content that portrays sedentary lifestyle positively. Block hate speech, illegal activities, or content disparaging athletes.", + "calibration_exemplars": { + "pass": [ + { "type": "domain", "value": "espn.com", "language": "en" }, + { "type": "domain", "value": "healthline.com", "language": "en" }, + { "type": "text", "value": "Lakers win championship in thrilling overtime finish", "language": "en" } + ], + "fail": [ + { "type": "domain", "value": "tabloid.example.com", "language": "en" }, + { "type": "text", "value": "Political scandal rocks the nation", "language": "en" }, + { "type": "audio_url", "value": "https://cdn.example.com/controversial-podcast.mp3" } + ] + }, + "floor": { + "url": "https://scope3.com/brand-safety-floor", + "name": "Scope3 Common Sense Brand Safety" + } +} +``` + +### Fields + +| Field | Description | +|-------|-------------| +| `standards_id` | Unique identifier for this standards configuration | +| `version` | Version of this configuration (semver recommended) | +| `name` | Human-readable name | +| `brand_ids` | Brand identifiers as defined in the Brand Manifest | +| `countries_all` | ISO country codes - standards apply in ALL listed countries | +| `channels_any` | Ad channels - standards apply to ANY of the listed channels | +| `policy` | Natural language policy describing acceptable and unacceptable content contexts | +| `calibration_exemplars` | Training/test set of content contexts (pass/fail) to calibrate policy interpretation | +| `floor` | Reference to external safety floor definition (URL + name) | + +### Error Response + +```json +{ + "errors": [ + { + "code": "STANDARDS_NOT_FOUND", + "message": "No standards found with ID 'invalid_id'" + } + ] +} +``` + +## Related Tasks + +- [calibrate_content](/docs/governance/content-standards/tasks/calibrate_content) - Collaborative calibration against these standards +- [list_content_standards](/docs/governance/content-standards/tasks/list_content_standards) - List available standards configurations diff --git a/docs/governance/content-standards/tasks/get_media_buy_artifacts.mdx b/docs/governance/content-standards/tasks/get_media_buy_artifacts.mdx new file mode 100644 index 0000000000..7b430da991 --- /dev/null +++ b/docs/governance/content-standards/tasks/get_media_buy_artifacts.mdx @@ -0,0 +1,205 @@ +--- +title: get_media_buy_artifacts +sidebar_position: 8 +--- + +# get_media_buy_artifacts + +Retrieve content artifacts from a media buy for validation. This is separate from `get_media_buy_delivery` which returns performance metrics - artifacts contain the actual content (text, images, video) where ads were placed. + +**Response time**: < 5s (batch of 1,000 artifacts) + +## Data Flow + +```mermaid +sequenceDiagram + participant Buyer as Buyer Agent + participant Seller as Seller Agent + participant Verifier as Verification Agent + + Buyer->>Seller: get_media_buy_artifacts (sampled or full) + Seller-->>Buyer: Artifacts with content + Buyer->>Verifier: validate_content_delivery + Verifier-->>Buyer: Validation results +``` + +The buyer requests artifacts from the seller using the same media buy parameters. The seller returns content samples based on the agreed sampling rate. The buyer then validates these against the verification agent. + +## Request + +**Schema**: [get-media-buy-artifacts-request.json](https://adcontextprotocol.org/schemas/v2/content-standards/get-media-buy-artifacts-request.json) + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `media_buy_id` | string | Yes | Media buy to get artifacts from | +| `package_ids` | array | No | Filter to specific packages | +| `sampling` | object | No | Sampling parameters (defaults to media buy agreement) | +| `time_range` | object | No | Filter to specific time period | +| `limit` | integer | No | Maximum artifacts to return (default: 1000) | +| `cursor` | string | No | Pagination cursor for large result sets | + +### Sampling Options + +```json +{ + "sampling": { + "rate": 0.25, + "method": "random" + } +} +``` + +| Method | Description | +|--------|-------------| +| `random` | Random sample across all deliveries | +| `stratified` | Sample proportionally across packages/properties | +| `recent` | Most recent deliveries first | +| `failures_only` | Only artifacts that failed local evaluation | + +## Response + +**Schema**: [get-media-buy-artifacts-response.json](https://adcontextprotocol.org/schemas/v2/content-standards/get-media-buy-artifacts-response.json) + +### Success Response + +```json +{ + "media_buy_id": "mb_nike_reddit_q1", + "artifacts": [ + { + "record_id": "imp_12345", + "timestamp": "2025-01-15T10:30:00Z", + "package_id": "pkg_feed_standard", + "artifact": { + "property_id": {"type": "domain", "value": "reddit.com"}, + "artifact_id": "r_fitness_abc123", + "assets": [ + {"type": "text", "role": "title", "content": "Best protein sources for muscle building", "language": "en"}, + {"type": "text", "role": "paragraph", "content": "Looking for recommendations on high-quality protein sources...", "language": "en"}, + {"type": "image", "url": "https://cdn.reddit.com/fitness-image.jpg", "alt_text": "Person lifting weights"} + ] + }, + "country": "US", + "channel": "social", + "brand_context": {"brand_id": "nike_global", "sku_id": "air_max_2025"}, + "local_verdict": "pass" + }, + { + "record_id": "imp_12346", + "timestamp": "2025-01-15T10:35:00Z", + "package_id": "pkg_feed_standard", + "artifact": { + "property_id": {"type": "domain", "value": "reddit.com"}, + "artifact_id": "r_news_politics_456", + "assets": [ + {"type": "text", "role": "title", "content": "Election Results Analysis", "language": "en"}, + {"type": "text", "role": "paragraph", "content": "The latest polling data shows...", "language": "en"} + ] + }, + "country": "US", + "channel": "social", + "brand_context": {"brand_id": "nike_global", "sku_id": "air_max_2025"}, + "local_verdict": "fail" + } + ], + "sampling_info": { + "total_deliveries": 100000, + "sampled_count": 1000, + "effective_rate": 0.01, + "method": "random" + }, + "pagination": { + "cursor": "eyJvZmZzZXQiOjEwMDB9", + "has_more": true + } +} +``` + +### Response Fields + +| Field | Description | +|-------|-------------| +| `artifacts` | Array of delivery records with full artifact content | +| `artifacts[].country` | ISO 3166-1 alpha-2 country code where delivery occurred | +| `artifacts[].channel` | Channel type (display, video, audio, social) | +| `artifacts[].brand_context` | Brand/SKU information for policy evaluation (schema TBD) | +| `artifacts[].local_verdict` | Seller's local model verdict (pass/fail/unevaluated) | +| `sampling_info` | How the sample was generated | +| `pagination` | Cursor for fetching more results | + +## Use Cases + +### Validate Sample Against Standards + +```python +# Get artifacts from seller +artifacts_response = seller_agent.get_media_buy_artifacts( + media_buy_id="mb_nike_reddit_q1", + sampling={"rate": 0.25, "method": "random"} +) + +# Convert to validation records +records = [ + { + "record_id": a["record_id"], + "timestamp": a["timestamp"], + "media_buy_id": artifacts_response["media_buy_id"], + "artifact": a["artifact"], + "country": a.get("country"), + "channel": a.get("channel"), + "brand_context": a.get("brand_context") + } + for a in artifacts_response["artifacts"] +] + +# Validate against verification agent +validation = verification_agent.validate_content_delivery( + standards_id="nike_brand_safety", + records=records +) + +# Check for drift between local and verified verdicts +for i, result in enumerate(validation["results"]): + local = artifacts_response["artifacts"][i]["local_verdict"] + verified = result["verdict"] + if local != verified: + print(f"Drift detected: {result['record_id']} - local={local}, verified={verified}") +``` + +### Focus on Local Failures + +```python +# Get only artifacts that failed local evaluation +failures = seller_agent.get_media_buy_artifacts( + media_buy_id="mb_nike_reddit_q1", + sampling={"method": "failures_only"}, + limit=100 +) + +# Verify these were correctly flagged +validation = verification_agent.validate_content_delivery( + standards_id="nike_brand_safety", + records=[{"record_id": a["record_id"], "artifact": a["artifact"]} + for a in failures["artifacts"]] +) + +# Check false positive rate +false_positives = sum(1 for r in validation["results"] if r["verdict"] == "pass") +print(f"False positive rate: {false_positives / len(failures['artifacts']):.1%}") +``` + +## Delivery vs Artifacts + +| Aspect | get_media_buy_delivery | get_media_buy_artifacts | +|--------|------------------------|-------------------------| +| **Purpose** | Performance reporting | Content validation | +| **Data size** | Small (metrics) | Large (full content) | +| **Frequency** | Regular reporting | Sampled validation | +| **Contains** | Impressions, clicks, spend | Text, images, video | +| **Consumer** | Buyer for optimization | Verification agent | + +## Related Tasks + +- [validate_content_delivery](/docs/governance/content-standards/tasks/validate_content_delivery) - Validate the artifacts +- [calibrate_content](/docs/governance/content-standards/tasks/calibrate_content) - Understand why artifacts pass/fail +- [get_media_buy_delivery](/docs/media-buy/task-reference/get_media_buy_delivery) - Get performance metrics diff --git a/docs/governance/content-standards/tasks/list_content_standards.mdx b/docs/governance/content-standards/tasks/list_content_standards.mdx new file mode 100644 index 0000000000..bb7c4d6d02 --- /dev/null +++ b/docs/governance/content-standards/tasks/list_content_standards.mdx @@ -0,0 +1,69 @@ +--- +title: list_content_standards +sidebar_position: 2 +--- + +# list_content_standards + +List available content standards configurations. + +**Response time**: < 500ms + +## Request + +**Schema**: [list-content-standards-request.json](https://adcontextprotocol.org/schemas/v2/content-standards/list-content-standards-request.json) + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `brand_ids` | array | No | Filter by brand identifiers | +| `countries` | array | No | Filter by country codes | +| `channels` | array | No | Filter by channels | + +## Response + +**Schema**: [list-content-standards-response.json](https://adcontextprotocol.org/schemas/v2/content-standards/list-content-standards-response.json) + +Returns an abbreviated list of standards configurations. Use [get_content_standards](/docs/governance/content-standards/tasks/get_content_standards) to retrieve full details including policy text and calibration data. + +### Success Response + +```json +{ + "standards": [ + { + "standards_id": "nike_emea_safety", + "version": "1.2.0", + "name": "Nike EMEA - all digital channels", + "brand_ids": ["nike"], + "countries_all": ["GB", "DE", "FR"], + "channels_any": ["display", "video", "ctv"] + }, + { + "standards_id": "nike_us_display", + "version": "1.0.0", + "name": "Nike US - display only", + "brand_ids": ["nike"], + "countries_all": ["US"], + "channels_any": ["display"] + } + ] +} +``` + +### Error Response + +```json +{ + "errors": [ + { + "code": "UNAUTHORIZED", + "message": "Invalid or expired token" + } + ] +} +``` + +## Related Tasks + +- [get_content_standards](/docs/governance/content-standards/tasks/get_content_standards) - Get a specific standards configuration +- [create_content_standards](/docs/governance/content-standards/tasks/create_content_standards) - Create a new configuration diff --git a/docs/governance/content-standards/tasks/update_content_standards.mdx b/docs/governance/content-standards/tasks/update_content_standards.mdx new file mode 100644 index 0000000000..b26faa0077 --- /dev/null +++ b/docs/governance/content-standards/tasks/update_content_standards.mdx @@ -0,0 +1,70 @@ +--- +title: update_content_standards +sidebar_position: 6 +--- + +# update_content_standards + +Update an existing content standards configuration. Creates a new version. + +**Response time**: < 1s + +## Request + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `standards_id` | string | Yes | ID of the standards configuration to update | +| `scope` | object | No | Updated scope | +| `policy` | string | No | Updated policy prompt | +| `calibration_exemplars` | object | No | Updated training exemplars (pass/fail) | +| `floor` | string | No | Updated safety floor | + +### Example Request + +```json +{ + "standards_id": "nike_emea_safety", + "policy": "Sports and fitness content is ideal. Lifestyle content about health and wellness is good. Entertainment content is generally acceptable. Avoid violence, controversial politics, adult themes. Block hate speech and illegal activities.", + "calibration_exemplars": { + "pass": [ + { "type": "domain", "value": "espn.com", "language": "en" }, + { "type": "domain", "value": "healthline.com", "language": "en" }, + { "type": "domain", "value": "runnersworld.com", "language": "en" } + ], + "fail": [ + { "type": "domain", "value": "tabloid.example.com", "language": "en" }, + { "type": "domain", "value": "gambling.example.com", "language": "en" } + ] + } +} +``` + +## Response + +### Success Response + +```json +{ + "standards_id": "nike_emea_safety", + "version": "1.3.0" +} +``` + +### Error Response + +```json +{ + "errors": [ + { + "code": "STANDARDS_NOT_FOUND", + "message": "No standards found with ID 'invalid_id'" + } + ] +} +``` + +## Related Tasks + +- [get_content_standards](/docs/governance/content-standards/tasks/get_content_standards) - Get current configuration +- [create_content_standards](/docs/governance/content-standards/tasks/create_content_standards) - Create a new configuration +- [delete_content_standards](/docs/governance/content-standards/tasks/delete_content_standards) - Delete a configuration diff --git a/docs/governance/content-standards/tasks/validate_content_delivery.mdx b/docs/governance/content-standards/tasks/validate_content_delivery.mdx new file mode 100644 index 0000000000..97f36c2b71 --- /dev/null +++ b/docs/governance/content-standards/tasks/validate_content_delivery.mdx @@ -0,0 +1,183 @@ +--- +title: validate_content_delivery +sidebar_position: 4 +--- + +# validate_content_delivery + +Validate delivery records against content safety policies. Designed for batch auditing of where ads were actually delivered. + +**Asynchronous**: Accept immediately, process in background. Returns a `validation_id` for status polling. + +## Data Flow + +Content artifacts are separate from delivery metrics. Use `get_media_buy_artifacts` to retrieve content for validation: + +```mermaid +sequenceDiagram + participant Buyer as Buyer Agent + participant Seller as Seller Agent + participant Verifier as Verification Agent + + Buyer->>Seller: get_media_buy_artifacts (sampled) + Seller-->>Buyer: Artifacts with content + Buyer->>Verifier: validate_content_delivery + Verifier-->>Buyer: Validation results +``` + +**Why through the buyer?** + +- The **buyer** owns the media buy and knows which `standards_id` applies +- The **buyer** requests artifacts from sellers (separate from performance metrics) +- The **buyer** is accountable for brand safety compliance +- The **verification agent** works on behalf of the buyer + +This keeps responsibilities clear: sellers provide content samples via `get_media_buy_artifacts`, buyers validate samples against the verification agent. + +## Request + +**Schema**: [validate-content-delivery-request.json](https://adcontextprotocol.org/schemas/v2/content-standards/validate-content-delivery-request.json) + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `standards_id` | string | Yes | Standards configuration to validate against | +| `records` | array | Yes | Delivery records to validate (max 10,000) | +| `feature_ids` | array | No | Specific features to evaluate (defaults to all) | +| `include_passed` | boolean | No | Include passed records in results (default: true) | + +### Delivery Record + +```json +{ + "record_id": "imp_12345", + "timestamp": "2025-01-15T10:30:00Z", + "media_buy_id": "mb_nike_reddit_q1", + "artifact": { + "property_id": {"type": "domain", "value": "example.com"}, + "artifact_id": "article_12345", + "assets": [ + {"type": "text", "role": "title", "content": "Article Title"} + ] + }, + "country": "US", + "channel": "display", + "brand_context": { + "brand_id": "nike_global", + "sku_id": "air_max_2025" + } +} +``` + +| Field | Required | Description | +|-------|----------|-------------| +| `record_id` | Yes | Unique identifier for this delivery record | +| `artifact` | Yes | Content artifact where ad was delivered | +| `media_buy_id` | No | Media buy this record belongs to (for multi-buy batches) | +| `timestamp` | No | When the delivery occurred | +| `country` | No | ISO 3166-1 alpha-2 country code for targeting context | +| `channel` | No | Channel type (display, video, audio, social) | +| `brand_context` | No | Brand/SKU information for policy evaluation (schema TBD) | + +## Response + +**Schema**: [validate-content-delivery-response.json](https://adcontextprotocol.org/schemas/v2/content-standards/validate-content-delivery-response.json) + +### Success Response + +```json +{ + "summary": { + "total_records": 1000, + "passed_records": 950, + "failed_records": 50, + "total_features": 5000, + "passed_features": 4750, + "failed_features": 250 + }, + "results": [ + { + "record_id": "imp_12345", + "features": [ + { + "feature_id": "brand_safety", + "status": "passed", + "value": "safe" + } + ] + }, + { + "record_id": "imp_12346", + "features": [ + { + "feature_id": "brand_safety", + "status": "failed", + "value": "high_risk", + "message": "Content contains violence" + } + ] + } + ] +} +``` + +## Use Cases + +### Post-Campaign Audit + +```python +def audit_campaign_delivery(campaign_id, standards_id, content_standards_agent): + """Audit all delivery records from a campaign.""" + # Fetch delivery records from your ad server + records = fetch_delivery_records(campaign_id) + + # Validate in batches + batch_size = 10000 + all_results = [] + + for i in range(0, len(records), batch_size): + batch = records[i:i + batch_size] + response = content_standards_agent.validate_content_delivery( + standards_id=standards_id, + records=batch + ) + all_results.extend(response["results"]) + + return all_results +``` + +### Real-Time Monitoring Sample + +```python +import random + +def sample_and_validate(records, standards_id, sample_size=1000): + """Validate a random sample for real-time monitoring.""" + sample = random.sample(records, min(sample_size, len(records))) + return content_standards_agent.validate_content_delivery( + standards_id=standards_id, + records=sample + ) +``` + +### Filter for Issues Only + +```python +# Only get failed records to reduce response size +response = content_standards_agent.validate_content_delivery( + standards_id="nike_emea_safety", + records=delivery_records, + include_passed=False # Only return failures +) + +for result in response["results"]: + print(f"Issue with {result['record_id']}") + for feature in result["features"]: + if feature["status"] == "failed": + print(f" - {feature['feature_id']}: {feature['message']}") +``` + +## Related Tasks + +- [get_media_buy_artifacts](/docs/governance/content-standards/tasks/get_media_buy_artifacts) - Get content artifacts from seller +- [calibrate_content](/docs/governance/content-standards/tasks/calibrate_content) - Understand why artifacts pass/fail +- [get_content_standards](/docs/governance/content-standards/tasks/get_content_standards) - Retrieve the policies diff --git a/docs/reference/error-codes.mdx b/docs/reference/error-codes.mdx index 0132e64cdf..0eac0041c3 100644 --- a/docs/reference/error-codes.mdx +++ b/docs/reference/error-codes.mdx @@ -425,6 +425,61 @@ Request exceeded maximum processing time. **Resolution**: Refine request parameters or retry. +## Content Standards Errors + +### STANDARDS_NOT_FOUND +Specified standards ID doesn't exist. + +**Example**: +```json +{ + "$schema": "https://adcontextprotocol.org/schemas/v2/core/error.json", + "code": "STANDARDS_NOT_FOUND", + "message": "No standards found with ID 'invalid_id'", + "details": { + "standards_id": "invalid_id" + } +} +``` + +**Resolution**: Use `list_content_standards` to find valid standards IDs. + +### STANDARDS_IN_USE +Cannot delete standards that are referenced by active media buys. + +**Example**: +```json +{ + "$schema": "https://adcontextprotocol.org/schemas/v2/core/error.json", + "code": "STANDARDS_IN_USE", + "message": "Cannot delete standards 'nike_emea_safety' - currently referenced by active media buys", + "details": { + "standards_id": "nike_emea_safety", + "active_media_buy_count": 3 + } +} +``` + +**Resolution**: Wait for media buys to complete before deleting. + +### STANDARDS_SCOPE_CONFLICT +New standards configuration conflicts with existing standards for the same scope. + +**Example**: +```json +{ + "$schema": "https://adcontextprotocol.org/schemas/v2/core/error.json", + "code": "STANDARDS_SCOPE_CONFLICT", + "message": "Standards already exist for brand 'nike' in countries ['GB', 'DE']", + "details": { + "conflicting_standards_id": "nike_emea_safety", + "overlapping_countries": ["GB", "DE"] + } +} +``` + +**Resolution**: Update existing standards or narrow scope to avoid overlap. + ## Data Errors ### DATA_QUALITY_ISSUE @@ -506,7 +561,10 @@ const PERMANENT_ERRORS = [ 'INSUFFICIENT_PERMISSIONS', 'SEGMENT_NOT_FOUND', 'PLATFORM_UNAUTHORIZED', - 'UNSUPPORTED_VERSION' + 'UNSUPPORTED_VERSION', + 'STANDARDS_NOT_FOUND', + 'STANDARDS_IN_USE', + 'STANDARDS_SCOPE_CONFLICT' ]; function isRetryable(errorCode: string): boolean { diff --git a/static/schemas/source/content-standards/artifact-webhook-payload.json b/static/schemas/source/content-standards/artifact-webhook-payload.json new file mode 100644 index 0000000000..63132ff516 --- /dev/null +++ b/static/schemas/source/content-standards/artifact-webhook-payload.json @@ -0,0 +1,72 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/content-standards/artifact-webhook-payload.json", + "title": "Artifact Webhook Payload", + "description": "Payload sent by sales agents to orchestrators when pushing content artifacts for governance validation. Complements get_media_buy_artifacts for push-based artifact delivery.", + "type": "object", + "properties": { + "media_buy_id": { + "type": "string", + "description": "Media buy identifier these artifacts belong to" + }, + "batch_id": { + "type": "string", + "description": "Unique identifier for this batch of artifacts. Use for deduplication and acknowledgment." + }, + "timestamp": { + "type": "string", + "format": "date-time", + "description": "When this batch was generated (ISO 8601)" + }, + "artifacts": { + "type": "array", + "description": "Content artifacts from delivered impressions", + "items": { + "type": "object", + "properties": { + "artifact": { + "$ref": "/schemas/content-standards/artifact.json", + "description": "The content artifact" + }, + "delivered_at": { + "type": "string", + "format": "date-time", + "description": "When the impression was delivered (ISO 8601)" + }, + "impression_id": { + "type": "string", + "description": "Optional impression identifier for correlation with delivery reports" + }, + "package_id": { + "type": "string", + "description": "Package within the media buy this artifact relates to" + } + }, + "required": ["artifact", "delivered_at"] + } + }, + "pagination": { + "type": "object", + "description": "Pagination info when batching large artifact sets", + "properties": { + "total_artifacts": { + "type": "integer", + "description": "Total artifacts in the delivery period" + }, + "batch_number": { + "type": "integer", + "description": "Current batch number (1-indexed)" + }, + "total_batches": { + "type": "integer", + "description": "Total batches for this delivery period" + } + } + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "required": ["media_buy_id", "batch_id", "timestamp", "artifacts"], + "additionalProperties": true +} diff --git a/static/schemas/source/content-standards/artifact.json b/static/schemas/source/content-standards/artifact.json new file mode 100644 index 0000000000..fda9f2af12 --- /dev/null +++ b/static/schemas/source/content-standards/artifact.json @@ -0,0 +1,309 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/content-standards/artifact.json", + "title": "Artifact", + "description": "Content artifact for safety and suitability evaluation. An artifact represents content adjacent to an ad placement - a news article, podcast segment, video chapter, or social post. Artifacts are collections of assets (text, images, video, audio) plus metadata and signals.", + "type": "object", + "properties": { + "property_id": { + "type": "object", + "description": "Identifier for the property where this artifact appears", + "properties": { + "type": { + "$ref": "/schemas/enums/identifier-types.json", + "description": "Type of property identifier" + }, + "value": { + "type": "string", + "description": "The identifier value" + } + }, + "required": ["type", "value"], + "additionalProperties": false + }, + "artifact_id": { + "type": "string", + "description": "Identifier for this artifact within the property. The property owner defines the scheme (e.g., 'article_12345', 'episode_42_segment_3', 'post_abc123')." + }, + "variant_id": { + "type": "string", + "description": "Identifies a specific variant of this artifact. Use for A/B tests, translations, or temporal versions. Examples: 'en', 'es-MX', 'v2', 'headline_test_b'. The combination of artifact_id + variant_id must be unique." + }, + "format_id": { + "type": "object", + "description": "Optional reference to a format definition. Uses the same format registry as creative formats.", + "properties": { + "agent_url": { + "type": "string", + "format": "uri", + "description": "Base URL of the agent that defines this format" + }, + "id": { + "type": "string", + "description": "Format identifier within that agent's registry" + } + }, + "required": ["agent_url", "id"], + "additionalProperties": false + }, + "url": { + "type": "string", + "format": "uri", + "description": "Optional URL for this artifact (web page, podcast feed, video page). Not all artifacts have URLs (e.g., Instagram content, podcast segments, TV scenes)." + }, + "published_time": { + "type": "string", + "format": "date-time", + "description": "When the artifact was published (ISO 8601 format)" + }, + "last_update_time": { + "type": "string", + "format": "date-time", + "description": "When the artifact was last modified (ISO 8601 format)" + }, + "assets": { + "type": "array", + "description": "Artifact assets in document flow order - text blocks, images, video, audio", + "items": { + "oneOf": [ + { + "type": "object", + "description": "Text block (paragraph, heading, etc.)", + "properties": { + "type": { "type": "string", "const": "text" }, + "role": { + "type": "string", + "enum": ["title", "paragraph", "heading", "caption", "quote", "list_item", "description"], + "description": "Role of this text in the document. Use 'title' for the main artifact title, 'description' for summaries." + }, + "content": { + "type": "string", + "description": "Text content" + }, + "language": { + "type": "string", + "description": "BCP 47 language tag for this text (e.g., 'en', 'es-MX'). Useful when artifact contains mixed-language content." + }, + "heading_level": { + "type": "integer", + "minimum": 1, + "maximum": 6, + "description": "Heading level (1-6), only for role=heading" + } + }, + "required": ["type", "content"] + }, + { + "type": "object", + "description": "Image asset", + "properties": { + "type": { "type": "string", "const": "image" }, + "url": { + "type": "string", + "format": "uri", + "description": "Image URL" + }, + "access": { + "$ref": "#/$defs/asset_access", + "description": "Authentication for secured URLs" + }, + "alt_text": { + "type": "string", + "description": "Alt text or image description" + }, + "caption": { + "type": "string", + "description": "Image caption" + }, + "width": { + "type": "integer", + "description": "Image width in pixels" + }, + "height": { + "type": "integer", + "description": "Image height in pixels" + } + }, + "required": ["type", "url"] + }, + { + "type": "object", + "description": "Video asset", + "properties": { + "type": { "type": "string", "const": "video" }, + "url": { + "type": "string", + "format": "uri", + "description": "Video URL" + }, + "access": { + "$ref": "#/$defs/asset_access", + "description": "Authentication for secured URLs" + }, + "duration_ms": { + "type": "integer", + "description": "Video duration in milliseconds" + }, + "transcript": { + "type": "string", + "description": "Video transcript" + }, + "transcript_source": { + "type": "string", + "enum": ["original_script", "subtitles", "closed_captions", "dub", "generated"], + "description": "How the transcript was generated" + }, + "thumbnail_url": { + "type": "string", + "format": "uri", + "description": "Video thumbnail URL" + } + }, + "required": ["type", "url"] + }, + { + "type": "object", + "description": "Audio asset", + "properties": { + "type": { "type": "string", "const": "audio" }, + "url": { + "type": "string", + "format": "uri", + "description": "Audio URL" + }, + "access": { + "$ref": "#/$defs/asset_access", + "description": "Authentication for secured URLs" + }, + "duration_ms": { + "type": "integer", + "description": "Audio duration in milliseconds" + }, + "transcript": { + "type": "string", + "description": "Audio transcript" + }, + "transcript_source": { + "type": "string", + "enum": ["original_script", "closed_captions", "generated"], + "description": "How the transcript was generated" + } + }, + "required": ["type", "url"] + } + ] + } + }, + "metadata": { + "type": "object", + "description": "Rich metadata extracted from the artifact", + "properties": { + "canonical": { + "type": "string", + "format": "uri", + "description": "Canonical URL" + }, + "author": { + "type": "string", + "description": "Artifact author name" + }, + "keywords": { + "type": "string", + "description": "Artifact keywords" + }, + "open_graph": { + "type": "object", + "description": "Open Graph protocol metadata", + "additionalProperties": true + }, + "twitter_card": { + "type": "object", + "description": "Twitter Card metadata", + "additionalProperties": true + }, + "json_ld": { + "type": "array", + "description": "JSON-LD structured data (schema.org)", + "items": { "type": "object" } + } + }, + "additionalProperties": true + }, + "identifiers": { + "type": "object", + "description": "Platform-specific identifiers for this artifact", + "properties": { + "apple_podcast_id": { + "type": "string", + "description": "Apple Podcasts ID" + }, + "spotify_show_id": { + "type": "string", + "description": "Spotify show ID" + }, + "podcast_guid": { + "type": "string", + "description": "Podcast GUID (from RSS feed)" + }, + "youtube_video_id": { + "type": "string", + "description": "YouTube video ID" + }, + "rss_url": { + "type": "string", + "format": "uri", + "description": "RSS feed URL" + } + }, + "additionalProperties": true + } + }, + "required": ["property_id", "artifact_id", "assets"], + "additionalProperties": true, + "$defs": { + "asset_access": { + "type": "object", + "description": "Authentication for accessing secured asset URLs", + "oneOf": [ + { + "type": "object", + "description": "Bearer token authentication", + "properties": { + "method": { "type": "string", "const": "bearer_token" }, + "token": { + "type": "string", + "description": "OAuth2 bearer token for Authorization header" + } + }, + "required": ["method", "token"] + }, + { + "type": "object", + "description": "Service account authentication (GCP, AWS)", + "properties": { + "method": { "type": "string", "const": "service_account" }, + "provider": { + "type": "string", + "enum": ["gcp", "aws"], + "description": "Cloud provider" + }, + "credentials": { + "type": "object", + "description": "Service account credentials", + "additionalProperties": true + } + }, + "required": ["method", "provider"] + }, + { + "type": "object", + "description": "Pre-signed URL (credentials embedded in URL)", + "properties": { + "method": { "type": "string", "const": "signed_url" } + }, + "required": ["method"] + } + ] + } + } +} diff --git a/static/schemas/source/content-standards/calibrate-content-request.json b/static/schemas/source/content-standards/calibrate-content-request.json new file mode 100644 index 0000000000..b259e500b1 --- /dev/null +++ b/static/schemas/source/content-standards/calibrate-content-request.json @@ -0,0 +1,18 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/content-standards/calibrate-content-request.json", + "title": "Calibrate Content Request", + "description": "Request parameters for evaluating content during calibration. Multi-turn dialogue is handled at the protocol layer via contextId.", + "type": "object", + "properties": { + "standards_id": { + "type": "string", + "description": "Standards configuration to calibrate against" + }, + "artifact": { + "$ref": "/schemas/content-standards/artifact.json", + "description": "Artifact to evaluate" + } + }, + "required": ["standards_id", "artifact"] +} diff --git a/static/schemas/source/content-standards/calibrate-content-response.json b/static/schemas/source/content-standards/calibrate-content-response.json new file mode 100644 index 0000000000..d6e24a814b --- /dev/null +++ b/static/schemas/source/content-standards/calibrate-content-response.json @@ -0,0 +1,73 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/content-standards/calibrate-content-response.json", + "title": "Calibrate Content Response", + "description": "Response payload with verdict and detailed explanations for collaborative calibration", + "type": "object", + "oneOf": [ + { + "type": "object", + "description": "Success response with detailed calibration feedback", + "properties": { + "verdict": { + "type": "string", + "enum": ["pass", "fail"], + "description": "Overall pass/fail verdict for the content evaluation" + }, + "confidence": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "Model confidence in the verdict (0-1)" + }, + "explanation": { + "type": "string", + "description": "Detailed natural language explanation of the decision" + }, + "features": { + "type": "array", + "description": "Per-feature breakdown with explanations", + "items": { + "type": "object", + "properties": { + "feature_id": { + "type": "string", + "description": "Which feature was evaluated (e.g., brand_safety, brand_suitability, competitor_adjacency)" + }, + "status": { + "type": "string", + "enum": ["passed", "failed", "warning", "unevaluated"], + "description": "Evaluation status for this feature" + }, + "explanation": { + "type": "string", + "description": "Human-readable explanation of why this feature passed or failed" + } + }, + "required": ["feature_id", "status"] + } + }, + "errors": { + "not": {}, + "description": "Field must not be present in success response" + } + }, + "required": ["verdict"] + }, + { + "type": "object", + "description": "Error response", + "properties": { + "errors": { + "type": "array", + "items": { "$ref": "/schemas/core/error.json" } + }, + "verdict": { + "not": {}, + "description": "Field must not be present in error response" + } + }, + "required": ["errors"] + } + ] +} diff --git a/static/schemas/source/content-standards/content-standards.json b/static/schemas/source/content-standards/content-standards.json new file mode 100644 index 0000000000..a88fb8135e --- /dev/null +++ b/static/schemas/source/content-standards/content-standards.json @@ -0,0 +1,80 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/content-standards/content-standards.json", + "title": "Content Standards", + "description": "A content standards configuration defining brand safety and suitability policies. Standards are scoped by brand, geography, and channel. Multiple standards can be active simultaneously for different scopes.", + "type": "object", + "properties": { + "standards_id": { + "type": "string", + "description": "Unique identifier for this standards configuration" + }, + "version": { + "type": "string", + "description": "Version of this standards configuration (semver recommended)" + }, + "name": { + "type": "string", + "description": "Human-readable name for this standards configuration" + }, + "brand_ids": { + "type": "array", + "items": { "type": "string" }, + "description": "Brand identifiers as defined in the Brand Manifest. Standards apply to all listed brands." + }, + "countries_all": { + "type": "array", + "items": { "type": "string" }, + "description": "ISO 3166-1 alpha-2 country codes. Standards apply in ALL listed countries (AND logic)." + }, + "channels_any": { + "type": "array", + "items": { "type": "string" }, + "description": "Advertising channels (display, video, audio, ctv, etc.). Standards apply to ANY of the listed channels (OR logic)." + }, + "policy": { + "type": "string", + "description": "Natural language policy describing acceptable and unacceptable content contexts. Used by LLMs and human reviewers to make judgments." + }, + "calibration_exemplars": { + "type": "object", + "description": "Training/test set to calibrate policy interpretation. Provides concrete examples of pass/fail decisions.", + "properties": { + "pass": { + "type": "array", + "items": { "$ref": "/schemas/content-standards/artifact.json" }, + "description": "Artifacts that pass the content standards" + }, + "fail": { + "type": "array", + "items": { "$ref": "/schemas/content-standards/artifact.json" }, + "description": "Artifacts that fail the content standards" + } + } + }, + "floor": { + "type": "object", + "description": "Safety floor baseline - a reference to an external floor definition. The floor defines universal content exclusions (hate speech, illegal content, etc.) that apply regardless of brand-specific policy.", + "properties": { + "url": { + "type": "string", + "format": "uri", + "description": "URL to the floor definition document (e.g., 'https://scope3.com/brand-safety-floor', 'https://example-publisher.com/content-guidelines')" + }, + "name": { + "type": "string", + "description": "Human-readable name for the floor (e.g., 'Scope3 Common Sense Brand Safety')" + }, + "version": { + "type": "string", + "description": "Version of the floor definition being referenced" + } + }, + "required": ["url"] + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "required": ["standards_id", "version"] +} diff --git a/static/schemas/source/content-standards/get-content-standards-request.json b/static/schemas/source/content-standards/get-content-standards-request.json new file mode 100644 index 0000000000..7790d22e0f --- /dev/null +++ b/static/schemas/source/content-standards/get-content-standards-request.json @@ -0,0 +1,20 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/content-standards/get-content-standards-request.json", + "title": "Get Content Standards Request", + "description": "Request parameters for retrieving content safety policies", + "type": "object", + "properties": { + "standards_id": { + "type": "string", + "description": "Identifier for the standards configuration to retrieve" + }, + "context": { + "$ref": "/schemas/core/context.json" + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "required": ["standards_id"] +} diff --git a/static/schemas/source/content-standards/get-content-standards-response.json b/static/schemas/source/content-standards/get-content-standards-response.json new file mode 100644 index 0000000000..cea2869f08 --- /dev/null +++ b/static/schemas/source/content-standards/get-content-standards-response.json @@ -0,0 +1,46 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/content-standards/get-content-standards-response.json", + "title": "Get Content Standards Response", + "description": "Response payload with content safety policies", + "type": "object", + "oneOf": [ + { + "type": "object", + "description": "Success response - returns the content standards configuration", + "allOf": [ + { "$ref": "/schemas/content-standards/content-standards.json" } + ], + "properties": { + "errors": { + "not": {}, + "description": "Field must not be present in success response" + }, + "context": { + "$ref": "/schemas/core/context.json" + } + } + }, + { + "type": "object", + "description": "Error response", + "properties": { + "errors": { + "type": "array", + "items": { "$ref": "/schemas/core/error.json" } + }, + "standards_id": { + "not": {}, + "description": "Field must not be present in error response" + }, + "context": { + "$ref": "/schemas/core/context.json" + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "required": ["errors"] + } + ] +} diff --git a/static/schemas/source/content-standards/get-media-buy-artifacts-request.json b/static/schemas/source/content-standards/get-media-buy-artifacts-request.json new file mode 100644 index 0000000000..90a33cbb77 --- /dev/null +++ b/static/schemas/source/content-standards/get-media-buy-artifacts-request.json @@ -0,0 +1,69 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/content-standards/get-media-buy-artifacts-request.json", + "title": "Get Media Buy Artifacts Request", + "description": "Request parameters for retrieving content artifacts from a media buy for validation", + "type": "object", + "properties": { + "media_buy_id": { + "type": "string", + "description": "Media buy to get artifacts from" + }, + "package_ids": { + "type": "array", + "items": { "type": "string" }, + "description": "Filter to specific packages within the media buy" + }, + "sampling": { + "type": "object", + "description": "Sampling parameters. Defaults to the sampling rate agreed in the media buy.", + "properties": { + "rate": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "Sampling rate (0-1). 1.0 = all deliveries, 0.25 = 25% sample." + }, + "method": { + "type": "string", + "enum": ["random", "stratified", "recent", "failures_only"], + "description": "How to select the sample" + } + } + }, + "time_range": { + "type": "object", + "description": "Filter to specific time period", + "properties": { + "start": { + "type": "string", + "format": "date-time", + "description": "Start of time range (inclusive)" + }, + "end": { + "type": "string", + "format": "date-time", + "description": "End of time range (exclusive)" + } + } + }, + "limit": { + "type": "integer", + "minimum": 1, + "maximum": 10000, + "default": 1000, + "description": "Maximum artifacts to return per request" + }, + "cursor": { + "type": "string", + "description": "Pagination cursor for fetching subsequent pages" + }, + "context": { + "$ref": "/schemas/core/context.json" + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "required": ["media_buy_id"] +} diff --git a/static/schemas/source/content-standards/get-media-buy-artifacts-response.json b/static/schemas/source/content-standards/get-media-buy-artifacts-response.json new file mode 100644 index 0000000000..fc1035b41b --- /dev/null +++ b/static/schemas/source/content-standards/get-media-buy-artifacts-response.json @@ -0,0 +1,142 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/content-standards/get-media-buy-artifacts-response.json", + "title": "Get Media Buy Artifacts Response", + "description": "Response containing content artifacts from a media buy for validation", + "type": "object", + "oneOf": [ + { + "type": "object", + "description": "Success response with artifacts", + "properties": { + "media_buy_id": { + "type": "string", + "description": "Media buy these artifacts belong to" + }, + "artifacts": { + "type": "array", + "description": "Delivery records with full artifact content", + "items": { + "type": "object", + "properties": { + "record_id": { + "type": "string", + "description": "Unique identifier for this delivery record" + }, + "timestamp": { + "type": "string", + "format": "date-time", + "description": "When the delivery occurred" + }, + "package_id": { + "type": "string", + "description": "Which package this delivery belongs to" + }, + "artifact": { + "$ref": "/schemas/content-standards/artifact.json", + "description": "Full artifact with content assets" + }, + "country": { + "type": "string", + "description": "ISO 3166-1 alpha-2 country code where delivery occurred" + }, + "channel": { + "type": "string", + "description": "Channel type (e.g., display, video, audio, social)" + }, + "brand_context": { + "type": "object", + "description": "Brand information for policy evaluation. Schema TBD - placeholder for brand identifiers.", + "properties": { + "brand_id": { + "type": "string", + "description": "Brand identifier" + }, + "sku_id": { + "type": "string", + "description": "Product/SKU identifier if applicable" + } + } + }, + "local_verdict": { + "type": "string", + "enum": ["pass", "fail", "unevaluated"], + "description": "Seller's local model verdict for this artifact" + } + }, + "required": ["record_id", "artifact"] + } + }, + "sampling_info": { + "type": "object", + "description": "Information about how the sample was generated", + "properties": { + "total_deliveries": { + "type": "integer", + "description": "Total deliveries in the time range" + }, + "sampled_count": { + "type": "integer", + "description": "Number of artifacts in this response" + }, + "effective_rate": { + "type": "number", + "description": "Actual sampling rate achieved" + }, + "method": { + "type": "string", + "enum": ["random", "stratified", "recent", "failures_only"], + "description": "Sampling method used" + } + } + }, + "pagination": { + "type": "object", + "description": "Pagination information for large result sets", + "properties": { + "cursor": { + "type": "string", + "description": "Cursor for fetching the next page" + }, + "has_more": { + "type": "boolean", + "description": "Whether more results are available" + } + } + }, + "errors": { + "not": {}, + "description": "Field must not be present in success response" + }, + "context": { + "$ref": "/schemas/core/context.json" + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "required": ["media_buy_id", "artifacts"] + }, + { + "type": "object", + "description": "Error response", + "properties": { + "errors": { + "type": "array", + "items": { "$ref": "/schemas/core/error.json" } + }, + "media_buy_id": { + "not": {}, + "description": "Field must not be present in error response" + }, + "context": { + "$ref": "/schemas/core/context.json" + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "required": ["errors"] + } + ] +} diff --git a/static/schemas/source/content-standards/list-content-standards-request.json b/static/schemas/source/content-standards/list-content-standards-request.json new file mode 100644 index 0000000000..42530fc698 --- /dev/null +++ b/static/schemas/source/content-standards/list-content-standards-request.json @@ -0,0 +1,31 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/content-standards/list-content-standards-request.json", + "title": "List Content Standards Request", + "description": "Request parameters for listing content standards configurations", + "type": "object", + "properties": { + "brand_ids": { + "type": "array", + "items": { "type": "string" }, + "description": "Filter by brand identifiers" + }, + "channels": { + "type": "array", + "items": { "type": "string" }, + "description": "Filter by channel (display, video, audio, ctv, etc.)" + }, + "countries": { + "type": "array", + "items": { "type": "string" }, + "description": "Filter by ISO 3166-1 alpha-2 country codes" + }, + "context": { + "$ref": "/schemas/core/context.json" + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "additionalProperties": true +} diff --git a/static/schemas/source/content-standards/list-content-standards-response.json b/static/schemas/source/content-standards/list-content-standards-response.json new file mode 100644 index 0000000000..b436bc3f43 --- /dev/null +++ b/static/schemas/source/content-standards/list-content-standards-response.json @@ -0,0 +1,52 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/content-standards/list-content-standards-response.json", + "title": "List Content Standards Response", + "description": "Response payload with list of content standards configurations", + "type": "object", + "oneOf": [ + { + "type": "object", + "description": "Success response - returns array of content standards", + "properties": { + "standards": { + "type": "array", + "items": { "$ref": "/schemas/content-standards/content-standards.json" }, + "description": "Array of content standards configurations matching the filter criteria" + }, + "errors": { + "not": {}, + "description": "Field must not be present in success response" + }, + "context": { + "$ref": "/schemas/core/context.json" + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "required": ["standards"] + }, + { + "type": "object", + "description": "Error response", + "properties": { + "errors": { + "type": "array", + "items": { "$ref": "/schemas/core/error.json" } + }, + "standards": { + "not": {}, + "description": "Field must not be present in error response" + }, + "context": { + "$ref": "/schemas/core/context.json" + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "required": ["errors"] + } + ] +} diff --git a/static/schemas/source/content-standards/validate-content-delivery-request.json b/static/schemas/source/content-standards/validate-content-delivery-request.json new file mode 100644 index 0000000000..4e35137b03 --- /dev/null +++ b/static/schemas/source/content-standards/validate-content-delivery-request.json @@ -0,0 +1,80 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/content-standards/validate-content-delivery-request.json", + "title": "Validate Content Delivery Request", + "description": "Request parameters for batch validating delivery records against content safety policies", + "type": "object", + "properties": { + "standards_id": { + "type": "string", + "description": "Standards configuration to validate against" + }, + "records": { + "type": "array", + "description": "Delivery records to validate (max 10,000)", + "maxItems": 10000, + "items": { + "type": "object", + "properties": { + "record_id": { + "type": "string", + "description": "Unique identifier for this delivery record" + }, + "media_buy_id": { + "type": "string", + "description": "Media buy this record belongs to (when batching across multiple buys)" + }, + "timestamp": { + "type": "string", + "format": "date-time", + "description": "When the delivery occurred" + }, + "artifact": { + "$ref": "/schemas/content-standards/artifact.json", + "description": "Artifact where ad was delivered" + }, + "country": { + "type": "string", + "description": "ISO 3166-1 alpha-2 country code where delivery occurred" + }, + "channel": { + "type": "string", + "description": "Channel type (e.g., display, video, audio, social)" + }, + "brand_context": { + "type": "object", + "description": "Brand information for policy evaluation. Schema TBD - placeholder for brand identifiers.", + "properties": { + "brand_id": { + "type": "string", + "description": "Brand identifier" + }, + "sku_id": { + "type": "string", + "description": "Product/SKU identifier if applicable" + } + } + } + }, + "required": ["record_id", "artifact"] + } + }, + "feature_ids": { + "type": "array", + "items": { "type": "string" }, + "description": "Specific features to evaluate (defaults to all)" + }, + "include_passed": { + "type": "boolean", + "default": true, + "description": "Include passed records in results" + }, + "context": { + "$ref": "/schemas/core/context.json" + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "required": ["standards_id", "records"] +} diff --git a/static/schemas/source/content-standards/validate-content-delivery-response.json b/static/schemas/source/content-standards/validate-content-delivery-response.json new file mode 100644 index 0000000000..1d1feeb1cd --- /dev/null +++ b/static/schemas/source/content-standards/validate-content-delivery-response.json @@ -0,0 +1,97 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/content-standards/validate-content-delivery-response.json", + "title": "Validate Content Delivery Response", + "description": "Response payload with per-record verdicts and optional feature breakdown", + "type": "object", + "oneOf": [ + { + "type": "object", + "description": "Success response", + "properties": { + "summary": { + "type": "object", + "description": "Summary counts across all records", + "properties": { + "total_records": { "type": "integer" }, + "passed_records": { "type": "integer" }, + "failed_records": { "type": "integer" } + }, + "required": ["total_records", "passed_records", "failed_records"] + }, + "results": { + "type": "array", + "description": "Per-record evaluation results", + "items": { + "type": "object", + "properties": { + "record_id": { + "type": "string", + "description": "Which delivery record was evaluated" + }, + "verdict": { + "type": "string", + "enum": ["pass", "fail"], + "description": "Overall pass/fail verdict for this record" + }, + "features": { + "type": "array", + "description": "Optional feature-level breakdown", + "items": { + "type": "object", + "properties": { + "feature_id": { "type": "string" }, + "status": { + "type": "string", + "enum": ["passed", "failed", "warning", "unevaluated"] + }, + "value": {}, + "message": { "type": "string" }, + "rule_id": { + "type": "string", + "description": "Which rule triggered this result (e.g., GARM category, Scope3 standard)" + } + }, + "required": ["feature_id", "status"] + } + } + }, + "required": ["record_id", "verdict"] + } + }, + "errors": { + "not": {}, + "description": "Field must not be present in success response" + }, + "context": { + "$ref": "/schemas/core/context.json" + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "required": ["summary", "results"] + }, + { + "type": "object", + "description": "Error response", + "properties": { + "errors": { + "type": "array", + "items": { "$ref": "/schemas/core/error.json" } + }, + "summary": { + "not": {}, + "description": "Field must not be present in error response" + }, + "context": { + "$ref": "/schemas/core/context.json" + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "required": ["errors"] + } + ] +} diff --git a/static/schemas/source/index.json b/static/schemas/source/index.json index 36eec37f3f..0944177caf 100644 --- a/static/schemas/source/index.json +++ b/static/schemas/source/index.json @@ -575,7 +575,7 @@ } }, "governance": { - "description": "Governance protocol for property governance, brand standards, and compliance", + "description": "Governance protocol for property governance, brand standards, content standards, and compliance", "supporting-schemas": { "property-feature-definition": { "$ref": "/schemas/property/property-feature-definition.json", @@ -608,6 +608,18 @@ "base-property-source": { "$ref": "/schemas/property/base-property-source.json", "description": "A source of properties for a property list - supports publisher+tags, publisher+property_ids, or direct identifiers" + }, + "content-standards": { + "$ref": "/schemas/content-standards/content-standards.json", + "description": "Reusable content standards configuration - defines brand safety/suitability policies with scope, policy, calibration exemplars, and lifecycle dates" + }, + "content-standards-artifact": { + "$ref": "/schemas/content-standards/artifact.json", + "description": "Content artifact for evaluation or calibration - represents content context where ad placements occur, identified by property_id + artifact_id" + }, + "artifact-webhook-payload": { + "$ref": "/schemas/content-standards/artifact-webhook-payload.json", + "description": "Webhook payload for content artifact delivery from sales agents to orchestrators" } }, "tasks": { @@ -670,6 +682,56 @@ "$ref": "/schemas/property/delete-property-list-response.json", "description": "Response payload for delete_property_list task" } + }, + "list-content-standards": { + "request": { + "$ref": "/schemas/content-standards/list-content-standards-request.json", + "description": "Request parameters for listing content standards configurations" + }, + "response": { + "$ref": "/schemas/content-standards/list-content-standards-response.json", + "description": "Response payload with list of content standards configurations" + } + }, + "get-content-standards": { + "request": { + "$ref": "/schemas/content-standards/get-content-standards-request.json", + "description": "Request parameters for retrieving content safety policies" + }, + "response": { + "$ref": "/schemas/content-standards/get-content-standards-response.json", + "description": "Response payload with content safety policies" + } + }, + "calibrate-content": { + "request": { + "$ref": "/schemas/content-standards/calibrate-content-request.json", + "description": "Request parameters for collaborative calibration dialogue" + }, + "response": { + "$ref": "/schemas/content-standards/calibrate-content-response.json", + "description": "Response payload with detailed explanations for policy alignment" + } + }, + "validate-content-delivery": { + "request": { + "$ref": "/schemas/content-standards/validate-content-delivery-request.json", + "description": "Request parameters for batch validating delivery records" + }, + "response": { + "$ref": "/schemas/content-standards/validate-content-delivery-response.json", + "description": "Response payload with batch validation results" + } + }, + "get-media-buy-artifacts": { + "request": { + "$ref": "/schemas/content-standards/get-media-buy-artifacts-request.json", + "description": "Request parameters for retrieving content artifacts from a media buy" + }, + "response": { + "$ref": "/schemas/content-standards/get-media-buy-artifacts-response.json", + "description": "Response payload with content artifacts for validation" + } } } }, diff --git a/static/schemas/source/media-buy/create-media-buy-request.json b/static/schemas/source/media-buy/create-media-buy-request.json index 47f5aa5822..648a9bcb3b 100644 --- a/static/schemas/source/media-buy/create-media-buy-request.json +++ b/static/schemas/source/media-buy/create-media-buy-request.json @@ -36,6 +36,76 @@ "$ref": "/schemas/core/reporting-webhook.json", "description": "Optional webhook configuration for automated reporting delivery" }, + "artifact_webhook": { + "$comment": "Webhook configuration for content artifact delivery - enables governance validation. Same authentication structure as reporting_webhook.", + "type": "object", + "description": "Optional webhook configuration for content artifact delivery. Used by governance agents to validate content adjacency. Seller pushes artifacts to this endpoint; orchestrator forwards to governance agent for validation.", + "properties": { + "url": { + "type": "string", + "format": "uri", + "description": "Webhook endpoint URL for artifact delivery" + }, + "token": { + "type": "string", + "description": "Optional client-provided token for webhook validation. Echoed back in webhook payload to validate request authenticity.", + "minLength": 16 + }, + "authentication": { + "type": "object", + "description": "Authentication configuration for webhook delivery (A2A-compatible)", + "properties": { + "schemes": { + "type": "array", + "description": "Array of authentication schemes. Supported: ['Bearer'] for simple token auth, ['HMAC-SHA256'] for signature verification (recommended for production)", + "items": { + "$ref": "/schemas/enums/auth-scheme.json" + }, + "minItems": 1, + "maxItems": 1 + }, + "credentials": { + "type": "string", + "description": "Credentials for authentication. For Bearer: token sent in Authorization header. For HMAC-SHA256: shared secret used to generate signature. Minimum 32 characters. Exchanged out-of-band during onboarding.", + "minLength": 32 + } + }, + "required": [ + "schemes", + "credentials" + ], + "additionalProperties": false + }, + "delivery_mode": { + "type": "string", + "enum": [ + "realtime", + "batched" + ], + "description": "How artifacts are delivered. 'realtime' pushes artifacts as impressions occur. 'batched' aggregates artifacts and pushes periodically (see batch_frequency)." + }, + "batch_frequency": { + "type": "string", + "enum": [ + "hourly", + "daily" + ], + "description": "For batched delivery, how often to push artifacts. Required when delivery_mode is 'batched'." + }, + "sampling_rate": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "Fraction of impressions to include (0-1). 1.0 = all impressions, 0.1 = 10% sample. Default: 1.0" + } + }, + "required": [ + "url", + "authentication", + "delivery_mode" + ], + "additionalProperties": true + }, "context": { "$ref": "/schemas/core/context.json" }, diff --git a/tests/schema-validation.test.cjs b/tests/schema-validation.test.cjs index 2d4b0a71c7..40727fc84d 100644 --- a/tests/schema-validation.test.cjs +++ b/tests/schema-validation.test.cjs @@ -130,33 +130,38 @@ function validateSchemaStructure(schemaPath, schema) { function validateCrossReferences(schemas) { const schemaIds = new Set(schemas.map(([_, schema]) => schema.$id)); const missingRefs = []; - + for (const [schemaPath, schema] of schemas) { // Find all $ref occurrences const refs = JSON.stringify(schema).match(/"\$ref":\s*"([^"]+)"/g) || []; - + for (const refMatch of refs) { const ref = refMatch.match(/"\$ref":\s*"([^"]+)"/)[1]; - + // Skip external references (http://, https://) if (ref.startsWith('http://') || ref.startsWith('https://')) { continue; } - + + // Skip internal references (#/$defs/..., #/properties/..., etc.) + if (ref.startsWith('#/')) { + continue; + } + // Check if referenced schema exists if (!schemaIds.has(ref)) { missingRefs.push({ schema: schemaPath, ref }); } } } - + if (missingRefs.length > 0) { - const errorMsg = missingRefs.map(({ schema, ref }) => + const errorMsg = missingRefs.map(({ schema, ref }) => `${path.basename(schema)} -> ${ref}` ).join(', '); return `Missing referenced schemas: ${errorMsg}`; } - + return true; } From 20c0b62fa2626b4c2aa1c9785f21b7ec412cfb9d Mon Sep 17 00:00:00 2001 From: Brian O'Kelley Date: Tue, 20 Jan 2026 05:51:24 -0500 Subject: [PATCH 22/34] feat: Add content standards create/update schemas and languages field (#806) * feat: Add content standards create/update schemas and languages field - Add create-content-standards-request/response.json schemas - Add update-content-standards-request/response.json schemas for incremental updates - Add languages field (BCP 47 tags) to content standards scope - Reference channels enum instead of string array for type safety - Remove version field from content standards response (keep spec clean) - Add webhook-authentication.json and webhook-config.json schemas - Update all content standards docs with languages examples Co-Authored-By: Claude Opus 4.5 * refactor: Address PR feedback on content standards schemas 1. Rename languages to languages_any for consistency with countries_all/channels_any - Clarifies OR logic: standards apply to content in ANY of listed languages - Content in unlisted languages is not covered by these standards 2. Add URL type to calibration exemplars (alongside domain type) - Enables page-level granularity for calibration - Example: { "type": "url", "value": "https://espn.com/nba/story/12345" } 3. Clarify floor documentation for vendor standards - Floors are industry-standard (GARM) or vendor-defined (IAS, DoubleVerify) - Seller agent retrieves floor definition from URL 4. Add language to scope conflict detection docs - Scope conflicts now consider country/channel/language combination Co-Authored-By: Claude Opus 4.5 * refactor: Remove domain type from calibration exemplars Domain-level references are too coarse for calibration - a domain can have millions of pages with varying content. Calibration exemplars now support: 1. URL references - specific pages to fetch and evaluate 2. Full artifacts - pre-extracted content (text, images, video, audio) Co-Authored-By: Claude Opus 4.5 * Remove floor field and update calibration exemplars - Remove floor field from content-standards schemas (content-standards.json, create-content-standards-request.json, update-content-standards-request.json) - Add documentation note that implementors MUST apply a brand safety floor, but AdCP does not define the floor specification - Update calibration exemplars to use URL type instead of domain type (domain is too coarse for calibration - need specific page URLs) Co-Authored-By: Claude Opus 4.5 --------- Co-authored-by: Claude Opus 4.5 --- .../implementation-guide.mdx | 12 +- docs/governance/content-standards/index.mdx | 5 +- .../tasks/create_content_standards.mdx | 48 +++---- .../tasks/get_content_standards.mdx | 29 ++--- .../tasks/list_content_standards.mdx | 20 ++- .../tasks/update_content_standards.mdx | 18 +-- .../content-standards/content-standards.json | 39 ++---- .../create-content-standards-request.json | 120 +++++++++++++++++ .../create-content-standards-response.json | 55 ++++++++ .../list-content-standards-request.json | 10 +- .../update-content-standards-request.json | 123 ++++++++++++++++++ .../update-content-standards-response.json | 42 ++++++ .../source/core/webhook-authentication.json | 28 ++++ .../schemas/source/core/webhook-config.json | 26 ++++ static/schemas/source/index.json | 24 +++- 15 files changed, 483 insertions(+), 116 deletions(-) create mode 100644 static/schemas/source/content-standards/create-content-standards-request.json create mode 100644 static/schemas/source/content-standards/create-content-standards-response.json create mode 100644 static/schemas/source/content-standards/update-content-standards-request.json create mode 100644 static/schemas/source/content-standards/update-content-standards-response.json create mode 100644 static/schemas/source/core/webhook-authentication.json create mode 100644 static/schemas/source/core/webhook-config.json diff --git a/docs/governance/content-standards/implementation-guide.mdx b/docs/governance/content-standards/implementation-guide.mdx index 18a22e0db6..c8efbcb77c 100644 --- a/docs/governance/content-standards/implementation-guide.mdx +++ b/docs/governance/content-standards/implementation-guide.mdx @@ -187,15 +187,11 @@ Brands create content standards through a governance agent. You might facilitate "policy": "Sports and fitness content is ideal. Avoid violence, adult themes, drugs.", "calibration_exemplars": { "pass": [ - { "type": "domain", "value": "espn.com" } + { "type": "url", "value": "https://espn.com/nba/story/_/id/12345/lakers-win", "language": "en" } ], "fail": [ - { "type": "domain", "value": "tabloid.example.com" } + { "type": "url", "value": "https://tabloid.example.com/celebrity-scandal", "language": "en" } ] - }, - "floor": { - "url": "https://scope3.com/brand-safety-floor", - "name": "Scope3 Common Sense Brand Safety" } } ``` @@ -290,10 +286,6 @@ Store standards configurations and expose them via `get_content_standards`: "calibration_exemplars": { "pass": [...], "fail": [...] - }, - "floor": { - "url": "https://scope3.com/brand-safety-floor", - "name": "Scope3 Common Sense Brand Safety" } } ``` diff --git a/docs/governance/content-standards/index.mdx b/docs/governance/content-standards/index.mdx index 5328d7a0f1..eda9db83a5 100644 --- a/docs/governance/content-standards/index.mdx +++ b/docs/governance/content-standards/index.mdx @@ -212,9 +212,8 @@ Buyers typically maintain multiple standards configurations for different contex ```json { - "standards_id": "coke_uk_tv_zero", - "name": "UK TV - Coca-Cola zero-calorie brands", - "brand_ids": ["coke_zero", "diet_coke"], + "standards_id": "uk_tv_zero_calorie", + "name": "UK TV - zero-calorie brands", "countries_all": ["GB"], "channels_any": ["ctv", "linear_tv"] } diff --git a/docs/governance/content-standards/tasks/create_content_standards.mdx b/docs/governance/content-standards/tasks/create_content_standards.mdx index 7c73c577cc..51859ca853 100644 --- a/docs/governance/content-standards/tasks/create_content_standards.mdx +++ b/docs/governance/content-standards/tasks/create_content_standards.mdx @@ -11,66 +11,56 @@ Create a new content standards configuration. ## Request +**Schema**: [create-content-standards-request.json](https://adcontextprotocol.org/schemas/v2/content-standards/create-content-standards-request.json) + | Parameter | Type | Required | Description | |-----------|------|----------|-------------| -| `scope` | object | Yes | Where this standards configuration applies | +| `scope` | object | Yes | Where this standards configuration applies (must include `languages_any`) | | `policy` | string | Yes | Natural language policy prompt | | `calibration_exemplars` | object | No | Training set of pass/fail artifacts for calibration | -| `floor` | object | No | Safety floor baseline - reference to external floor definition | + +:::note[Brand Safety Floor Requirement] +Implementors MUST apply a brand safety floor regardless of what policy is defined in content standards. Content that violates the floor (hate speech, illegal content, etc.) must be excluded even when no content standards are specified. AdCP does not define the floor specification; this is left to implementors and industry standards (e.g., GARM categories). +::: ### Example Request ```json { "scope": { - "brand_ids": ["nike"], "countries_all": ["GB", "DE", "FR"], "channels_any": ["display", "video", "ctv"], - "description": "Nike EMEA - all digital channels" + "languages_any": ["en", "de", "fr"], + "description": "EMEA - all digital channels" }, "policy": "Sports and fitness content is ideal. Lifestyle content about health and wellness is good. Entertainment content is generally acceptable. Avoid content about violence, controversial political topics, adult themes, or content that portrays sedentary lifestyle positively.", "calibration_exemplars": { "pass": [ - { "type": "domain", "value": "espn.com", "language": "en" }, - { "type": "domain", "value": "healthline.com", "language": "en" } + { "type": "url", "value": "https://espn.com/nba/story/_/id/12345/lakers-championship", "language": "en" }, + { "type": "url", "value": "https://healthline.com/fitness/cardio-workout", "language": "en" } ], "fail": [ - { "type": "domain", "value": "tabloid.example.com", "language": "en" } + { "type": "url", "value": "https://tabloid.example.com/celebrity-scandal", "language": "en" }, + { "type": "url", "value": "https://news.example.com/controversial-politics-article", "language": "en" } ] - }, - "floor": { - "url": "https://scope3.com/brand-safety-floor", - "name": "Scope3 Common Sense Brand Safety" } } ``` ## Response +**Schema**: [create-content-standards-response.json](https://adcontextprotocol.org/schemas/v2/content-standards/create-content-standards-response.json) + ### Success Response ```json { - "standards_id": "nike_emea_safety", - "version": "1.0.0" + "standards_id": "emea_digital_safety" } ``` ### Error Responses -**Invalid Scope:** - -```json -{ - "errors": [ - { - "code": "INVALID_SCOPE", - "message": "At least one brand_id is required" - } - ] -} -``` - **Scope Conflict:** ```json @@ -78,8 +68,8 @@ Create a new content standards configuration. "errors": [ { "code": "SCOPE_CONFLICT", - "message": "Standards already exist for brand 'nike' in country 'DE' on channel 'display'", - "conflicting_standards_id": "nike_emea_safety" + "message": "Standards already exist for country 'DE' on channel 'display'", + "conflicting_standards_id": "emea_digital_safety" } ] } @@ -87,7 +77,7 @@ Create a new content standards configuration. ## Scope Conflict Handling -Multiple standards cannot have overlapping scopes for the same brand/country/channel combination. When creating standards that would conflict: +Multiple standards cannot have overlapping scopes for the same country/channel/language combination. When creating standards that would conflict: 1. **Check existing standards** - Use [list_content_standards](/docs/governance/content-standards/tasks/list_content_standards) filtered by your scope 2. **Update rather than create** - If standards already exist, use [update_content_standards](/docs/governance/content-standards/tasks/update_content_standards) diff --git a/docs/governance/content-standards/tasks/get_content_standards.mdx b/docs/governance/content-standards/tasks/get_content_standards.mdx index 74229890e4..dec5de452e 100644 --- a/docs/governance/content-standards/tasks/get_content_standards.mdx +++ b/docs/governance/content-standards/tasks/get_content_standards.mdx @@ -23,28 +23,21 @@ Retrieve content safety policies for a specific standards configuration. ```json { - "standards_id": "nike_emea_safety", - "version": "1.2.0", - "name": "Nike EMEA - all digital channels", - "brand_ids": ["nike"], + "standards_id": "emea_digital_safety", + "name": "EMEA - all digital channels", "countries_all": ["GB", "DE", "FR"], "channels_any": ["display", "video", "ctv"], + "languages_any": ["en", "de", "fr"], "policy": "Sports and fitness content is ideal. Lifestyle content about health and wellness is good. Entertainment content is generally acceptable. Avoid content about violence, controversial political topics, adult themes, or content that portrays sedentary lifestyle positively. Block hate speech, illegal activities, or content disparaging athletes.", "calibration_exemplars": { "pass": [ - { "type": "domain", "value": "espn.com", "language": "en" }, - { "type": "domain", "value": "healthline.com", "language": "en" }, - { "type": "text", "value": "Lakers win championship in thrilling overtime finish", "language": "en" } + { "type": "url", "value": "https://espn.com/nba/story/_/id/12345/lakers-championship", "language": "en" }, + { "type": "url", "value": "https://healthline.com/fitness/cardio-workout", "language": "en" } ], "fail": [ - { "type": "domain", "value": "tabloid.example.com", "language": "en" }, - { "type": "text", "value": "Political scandal rocks the nation", "language": "en" }, - { "type": "audio_url", "value": "https://cdn.example.com/controversial-podcast.mp3" } + { "type": "url", "value": "https://tabloid.example.com/celebrity-scandal", "language": "en" }, + { "type": "url", "value": "https://news.example.com/controversial-politics-article", "language": "en" } ] - }, - "floor": { - "url": "https://scope3.com/brand-safety-floor", - "name": "Scope3 Common Sense Brand Safety" } } ``` @@ -54,14 +47,16 @@ Retrieve content safety policies for a specific standards configuration. | Field | Description | |-------|-------------| | `standards_id` | Unique identifier for this standards configuration | -| `version` | Version of this configuration (semver recommended) | | `name` | Human-readable name | -| `brand_ids` | Brand identifiers as defined in the Brand Manifest | | `countries_all` | ISO country codes - standards apply in ALL listed countries | | `channels_any` | Ad channels - standards apply to ANY of the listed channels | +| `languages_any` | BCP 47 language tags - standards apply to content in ANY of these languages | | `policy` | Natural language policy describing acceptable and unacceptable content contexts | | `calibration_exemplars` | Training/test set of content contexts (pass/fail) to calibrate policy interpretation | -| `floor` | Reference to external safety floor definition (URL + name) | + +:::note[Brand Safety Floor Requirement] +Implementors MUST apply a brand safety floor regardless of what policy is defined. AdCP does not define the floor specification. +::: ### Error Response diff --git a/docs/governance/content-standards/tasks/list_content_standards.mdx b/docs/governance/content-standards/tasks/list_content_standards.mdx index bb7c4d6d02..cdaea651ae 100644 --- a/docs/governance/content-standards/tasks/list_content_standards.mdx +++ b/docs/governance/content-standards/tasks/list_content_standards.mdx @@ -15,9 +15,9 @@ List available content standards configurations. | Parameter | Type | Required | Description | |-----------|------|----------|-------------| -| `brand_ids` | array | No | Filter by brand identifiers | | `countries` | array | No | Filter by country codes | | `channels` | array | No | Filter by channels | +| `languages` | array | No | Filter by BCP 47 language tags | ## Response @@ -31,20 +31,18 @@ Returns an abbreviated list of standards configurations. Use [get_content_standa { "standards": [ { - "standards_id": "nike_emea_safety", - "version": "1.2.0", - "name": "Nike EMEA - all digital channels", - "brand_ids": ["nike"], + "standards_id": "emea_digital_safety", + "name": "EMEA - all digital channels", "countries_all": ["GB", "DE", "FR"], - "channels_any": ["display", "video", "ctv"] + "channels_any": ["display", "video", "ctv"], + "languages": ["en", "de", "fr"] }, { - "standards_id": "nike_us_display", - "version": "1.0.0", - "name": "Nike US - display only", - "brand_ids": ["nike"], + "standards_id": "us_display_only", + "name": "US - display only", "countries_all": ["US"], - "channels_any": ["display"] + "channels_any": ["display"], + "languages": ["en"] } ] } diff --git a/docs/governance/content-standards/tasks/update_content_standards.mdx b/docs/governance/content-standards/tasks/update_content_standards.mdx index b26faa0077..4f2fb5bc29 100644 --- a/docs/governance/content-standards/tasks/update_content_standards.mdx +++ b/docs/governance/content-standards/tasks/update_content_standards.mdx @@ -11,13 +11,14 @@ Update an existing content standards configuration. Creates a new version. ## Request +**Schema**: [update-content-standards-request.json](https://adcontextprotocol.org/schemas/v2/content-standards/update-content-standards-request.json) + | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `standards_id` | string | Yes | ID of the standards configuration to update | | `scope` | object | No | Updated scope | | `policy` | string | No | Updated policy prompt | | `calibration_exemplars` | object | No | Updated training exemplars (pass/fail) | -| `floor` | string | No | Updated safety floor | ### Example Request @@ -27,13 +28,13 @@ Update an existing content standards configuration. Creates a new version. "policy": "Sports and fitness content is ideal. Lifestyle content about health and wellness is good. Entertainment content is generally acceptable. Avoid violence, controversial politics, adult themes. Block hate speech and illegal activities.", "calibration_exemplars": { "pass": [ - { "type": "domain", "value": "espn.com", "language": "en" }, - { "type": "domain", "value": "healthline.com", "language": "en" }, - { "type": "domain", "value": "runnersworld.com", "language": "en" } + { "type": "url", "value": "https://espn.com/nba/story/_/id/12345/lakers-win", "language": "en" }, + { "type": "url", "value": "https://healthline.com/fitness/cardio-workout", "language": "en" }, + { "type": "url", "value": "https://runnersworld.com/training/marathon-tips", "language": "en" } ], "fail": [ - { "type": "domain", "value": "tabloid.example.com", "language": "en" }, - { "type": "domain", "value": "gambling.example.com", "language": "en" } + { "type": "url", "value": "https://tabloid.example.com/celebrity-scandal", "language": "en" }, + { "type": "url", "value": "https://gambling.example.com/betting-guide", "language": "en" } ] } } @@ -41,12 +42,13 @@ Update an existing content standards configuration. Creates a new version. ## Response +**Schema**: [update-content-standards-response.json](https://adcontextprotocol.org/schemas/v2/content-standards/update-content-standards-response.json) + ### Success Response ```json { - "standards_id": "nike_emea_safety", - "version": "1.3.0" + "standards_id": "nike_emea_safety" } ``` diff --git a/static/schemas/source/content-standards/content-standards.json b/static/schemas/source/content-standards/content-standards.json index a88fb8135e..26abbbfef1 100644 --- a/static/schemas/source/content-standards/content-standards.json +++ b/static/schemas/source/content-standards/content-standards.json @@ -9,28 +9,25 @@ "type": "string", "description": "Unique identifier for this standards configuration" }, - "version": { - "type": "string", - "description": "Version of this standards configuration (semver recommended)" - }, "name": { "type": "string", "description": "Human-readable name for this standards configuration" }, - "brand_ids": { - "type": "array", - "items": { "type": "string" }, - "description": "Brand identifiers as defined in the Brand Manifest. Standards apply to all listed brands." - }, "countries_all": { "type": "array", "items": { "type": "string" }, "description": "ISO 3166-1 alpha-2 country codes. Standards apply in ALL listed countries (AND logic)." }, "channels_any": { + "type": "array", + "items": { "$ref": "/schemas/enums/channels.json" }, + "description": "Advertising channels. Standards apply to ANY of the listed channels (OR logic)." + }, + "languages_any": { "type": "array", "items": { "type": "string" }, - "description": "Advertising channels (display, video, audio, ctv, etc.). Standards apply to ANY of the listed channels (OR logic)." + "minItems": 1, + "description": "BCP 47 language tags (e.g., 'en', 'de', 'fr'). Standards apply to content in ANY of these languages (OR logic). Content in unlisted languages is not covered by these standards." }, "policy": { "type": "string", @@ -52,29 +49,9 @@ } } }, - "floor": { - "type": "object", - "description": "Safety floor baseline - a reference to an external floor definition. The floor defines universal content exclusions (hate speech, illegal content, etc.) that apply regardless of brand-specific policy.", - "properties": { - "url": { - "type": "string", - "format": "uri", - "description": "URL to the floor definition document (e.g., 'https://scope3.com/brand-safety-floor', 'https://example-publisher.com/content-guidelines')" - }, - "name": { - "type": "string", - "description": "Human-readable name for the floor (e.g., 'Scope3 Common Sense Brand Safety')" - }, - "version": { - "type": "string", - "description": "Version of the floor definition being referenced" - } - }, - "required": ["url"] - }, "ext": { "$ref": "/schemas/core/ext.json" } }, - "required": ["standards_id", "version"] + "required": ["standards_id"] } diff --git a/static/schemas/source/content-standards/create-content-standards-request.json b/static/schemas/source/content-standards/create-content-standards-request.json new file mode 100644 index 0000000000..bbd8c6f84f --- /dev/null +++ b/static/schemas/source/content-standards/create-content-standards-request.json @@ -0,0 +1,120 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/content-standards/create-content-standards-request.json", + "title": "Create Content Standards Request", + "description": "Request parameters for creating a new content standards configuration", + "type": "object", + "properties": { + "scope": { + "type": "object", + "description": "Where this standards configuration applies", + "properties": { + "countries_all": { + "type": "array", + "items": { "type": "string" }, + "description": "ISO 3166-1 alpha-2 country codes. Standards apply in ALL listed countries (AND logic)." + }, + "channels_any": { + "type": "array", + "items": { "$ref": "/schemas/enums/channels.json" }, + "description": "Advertising channels. Standards apply to ANY of the listed channels (OR logic)." + }, + "languages_any": { + "type": "array", + "items": { "type": "string" }, + "minItems": 1, + "description": "BCP 47 language tags (e.g., 'en', 'de', 'fr'). Standards apply to content in ANY of these languages (OR logic). Content in unlisted languages is not covered by these standards." + }, + "description": { + "type": "string", + "description": "Human-readable description of this scope" + } + }, + "required": ["languages_any"] + }, + "policy": { + "type": "string", + "description": "Natural language policy describing acceptable and unacceptable content contexts. Used by LLMs and human reviewers to make judgments." + }, + "calibration_exemplars": { + "type": "object", + "description": "Training/test set to calibrate policy interpretation. Use URL references for pages to be fetched and analyzed, or full artifacts for pre-extracted content.", + "properties": { + "pass": { + "type": "array", + "items": { + "oneOf": [ + { + "type": "object", + "description": "URL reference - specific page to fetch and evaluate", + "properties": { + "type": { + "type": "string", + "const": "url", + "description": "Indicates this is a URL reference" + }, + "value": { + "type": "string", + "format": "uri", + "description": "Full URL to a specific page (e.g., 'https://espn.com/nba/story/_/id/12345/lakers-win')" + }, + "language": { + "type": "string", + "description": "BCP 47 language tag for content at this URL" + } + }, + "required": ["type", "value"] + }, + { + "$ref": "/schemas/content-standards/artifact.json", + "description": "Full artifact with pre-extracted content (text, images, video, audio)" + } + ] + }, + "description": "Content that passes the standards" + }, + "fail": { + "type": "array", + "items": { + "oneOf": [ + { + "type": "object", + "description": "URL reference - specific page to fetch and evaluate", + "properties": { + "type": { + "type": "string", + "const": "url", + "description": "Indicates this is a URL reference" + }, + "value": { + "type": "string", + "format": "uri", + "description": "Full URL to a specific page (e.g., 'https://news.example.com/controversial-article')" + }, + "language": { + "type": "string", + "description": "BCP 47 language tag for content at this URL" + } + }, + "required": ["type", "value"] + }, + { + "$ref": "/schemas/content-standards/artifact.json", + "description": "Full artifact with pre-extracted content (text, images, video, audio)" + } + ] + }, + "description": "Content that fails the standards" + } + } + }, + "context": { + "$ref": "/schemas/core/context.json" + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "required": ["scope", "policy"], + "additionalProperties": true +} diff --git a/static/schemas/source/content-standards/create-content-standards-response.json b/static/schemas/source/content-standards/create-content-standards-response.json new file mode 100644 index 0000000000..80bdc5cdb5 --- /dev/null +++ b/static/schemas/source/content-standards/create-content-standards-response.json @@ -0,0 +1,55 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/content-standards/create-content-standards-response.json", + "title": "Create Content Standards Response", + "description": "Response payload for creating a content standards configuration", + "type": "object", + "oneOf": [ + { + "type": "object", + "description": "Success response - returns the created standards identifier", + "properties": { + "standards_id": { + "type": "string", + "description": "Unique identifier for the created standards configuration" + }, + "errors": { + "not": {}, + "description": "Field must not be present in success response" + }, + "context": { + "$ref": "/schemas/core/context.json" + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "required": ["standards_id"] + }, + { + "type": "object", + "description": "Error response", + "properties": { + "errors": { + "type": "array", + "items": { "$ref": "/schemas/core/error.json" } + }, + "conflicting_standards_id": { + "type": "string", + "description": "If the error is a scope conflict, the ID of the existing standards that conflict" + }, + "standards_id": { + "not": {}, + "description": "Field must not be present in error response" + }, + "context": { + "$ref": "/schemas/core/context.json" + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "required": ["errors"] + } + ] +} diff --git a/static/schemas/source/content-standards/list-content-standards-request.json b/static/schemas/source/content-standards/list-content-standards-request.json index 42530fc698..fc5f246cac 100644 --- a/static/schemas/source/content-standards/list-content-standards-request.json +++ b/static/schemas/source/content-standards/list-content-standards-request.json @@ -5,15 +5,15 @@ "description": "Request parameters for listing content standards configurations", "type": "object", "properties": { - "brand_ids": { + "channels": { "type": "array", - "items": { "type": "string" }, - "description": "Filter by brand identifiers" + "items": { "$ref": "/schemas/enums/channels.json" }, + "description": "Filter by channel" }, - "channels": { + "languages": { "type": "array", "items": { "type": "string" }, - "description": "Filter by channel (display, video, audio, ctv, etc.)" + "description": "Filter by BCP 47 language tags" }, "countries": { "type": "array", diff --git a/static/schemas/source/content-standards/update-content-standards-request.json b/static/schemas/source/content-standards/update-content-standards-request.json new file mode 100644 index 0000000000..9f0e73d27e --- /dev/null +++ b/static/schemas/source/content-standards/update-content-standards-request.json @@ -0,0 +1,123 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/content-standards/update-content-standards-request.json", + "title": "Update Content Standards Request", + "description": "Request parameters for updating an existing content standards configuration. Creates a new version.", + "type": "object", + "properties": { + "standards_id": { + "type": "string", + "description": "ID of the standards configuration to update" + }, + "scope": { + "type": "object", + "description": "Updated scope for where this standards configuration applies", + "properties": { + "countries_all": { + "type": "array", + "items": { "type": "string" }, + "description": "ISO 3166-1 alpha-2 country codes. Standards apply in ALL listed countries (AND logic)." + }, + "channels_any": { + "type": "array", + "items": { "$ref": "/schemas/enums/channels.json" }, + "description": "Advertising channels. Standards apply to ANY of the listed channels (OR logic)." + }, + "languages_any": { + "type": "array", + "items": { "type": "string" }, + "minItems": 1, + "description": "BCP 47 language tags (e.g., 'en', 'de', 'fr'). Standards apply to content in ANY of these languages (OR logic). Content in unlisted languages is not covered by these standards." + }, + "description": { + "type": "string", + "description": "Human-readable description of this scope" + } + } + }, + "policy": { + "type": "string", + "description": "Updated natural language policy describing acceptable and unacceptable content contexts." + }, + "calibration_exemplars": { + "type": "object", + "description": "Updated training/test set to calibrate policy interpretation. Use URL references for pages to be fetched and analyzed, or full artifacts for pre-extracted content.", + "properties": { + "pass": { + "type": "array", + "items": { + "oneOf": [ + { + "type": "object", + "description": "URL reference - specific page to fetch and evaluate", + "properties": { + "type": { + "type": "string", + "const": "url", + "description": "Indicates this is a URL reference" + }, + "value": { + "type": "string", + "format": "uri", + "description": "Full URL to a specific page (e.g., 'https://espn.com/nba/story/_/id/12345/lakers-win')" + }, + "language": { + "type": "string", + "description": "BCP 47 language tag for content at this URL" + } + }, + "required": ["type", "value"] + }, + { + "$ref": "/schemas/content-standards/artifact.json", + "description": "Full artifact with pre-extracted content (text, images, video, audio)" + } + ] + }, + "description": "Content that passes the standards" + }, + "fail": { + "type": "array", + "items": { + "oneOf": [ + { + "type": "object", + "description": "URL reference - specific page to fetch and evaluate", + "properties": { + "type": { + "type": "string", + "const": "url", + "description": "Indicates this is a URL reference" + }, + "value": { + "type": "string", + "format": "uri", + "description": "Full URL to a specific page (e.g., 'https://news.example.com/controversial-article')" + }, + "language": { + "type": "string", + "description": "BCP 47 language tag for content at this URL" + } + }, + "required": ["type", "value"] + }, + { + "$ref": "/schemas/content-standards/artifact.json", + "description": "Full artifact with pre-extracted content (text, images, video, audio)" + } + ] + }, + "description": "Content that fails the standards" + } + } + }, + "context": { + "$ref": "/schemas/core/context.json" + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "required": ["standards_id"], + "additionalProperties": true +} diff --git a/static/schemas/source/content-standards/update-content-standards-response.json b/static/schemas/source/content-standards/update-content-standards-response.json new file mode 100644 index 0000000000..26d9d5229a --- /dev/null +++ b/static/schemas/source/content-standards/update-content-standards-response.json @@ -0,0 +1,42 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/content-standards/update-content-standards-response.json", + "title": "Update Content Standards Response", + "description": "Response from updating a content standards configuration", + "type": "object", + "properties": { + "standards_id": { + "type": "string", + "description": "ID of the updated standards configuration" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "properties": { + "code": { + "type": "string", + "description": "Error code (e.g., STANDARDS_NOT_FOUND, SCOPE_CONFLICT)" + }, + "message": { + "type": "string", + "description": "Human-readable error message" + } + }, + "required": ["code", "message"] + }, + "description": "Errors that occurred during the update" + }, + "conflicting_standards_id": { + "type": "string", + "description": "If scope change conflicts with another configuration, the ID of the conflicting standards" + }, + "context": { + "$ref": "/schemas/core/context.json" + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "additionalProperties": true +} diff --git a/static/schemas/source/core/webhook-authentication.json b/static/schemas/source/core/webhook-authentication.json new file mode 100644 index 0000000000..504b2e3804 --- /dev/null +++ b/static/schemas/source/core/webhook-authentication.json @@ -0,0 +1,28 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/core/webhook-authentication.json", + "title": "Webhook Authentication", + "description": "Authentication configuration for webhook delivery. Supports Bearer tokens for simple authentication or HMAC-SHA256 for signature-based verification (recommended for production). Compatible with A2A PushNotificationConfig structure.", + "type": "object", + "properties": { + "schemes": { + "type": "array", + "description": "Array of authentication schemes. Supported: ['Bearer'] for simple token auth, ['HMAC-SHA256'] for signature verification (recommended for production)", + "items": { + "$ref": "/schemas/enums/auth-scheme.json" + }, + "minItems": 1, + "maxItems": 1 + }, + "credentials": { + "type": "string", + "description": "Credentials for authentication. For Bearer: token sent in Authorization header. For HMAC-SHA256: shared secret used to generate signature. Minimum 32 characters. Exchanged out-of-band during onboarding.", + "minLength": 32 + } + }, + "required": [ + "schemes", + "credentials" + ], + "additionalProperties": false +} diff --git a/static/schemas/source/core/webhook-config.json b/static/schemas/source/core/webhook-config.json new file mode 100644 index 0000000000..0d1fe097a2 --- /dev/null +++ b/static/schemas/source/core/webhook-config.json @@ -0,0 +1,26 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/core/webhook-config.json", + "title": "Webhook Config", + "description": "Base webhook configuration for authenticated HTTP callbacks. Defines the common structure for url, token, and authentication used by reporting_webhook, artifact_webhook, and other webhook configurations. Note: Due to JSON Schema limitations with allOf + additionalProperties:false, consuming schemas inline these properties rather than using $ref composition.", + "type": "object", + "properties": { + "url": { + "type": "string", + "format": "uri", + "description": "Webhook endpoint URL" + }, + "token": { + "type": "string", + "description": "Optional client-provided token for webhook validation. Echoed back in webhook payload to validate request authenticity.", + "minLength": 16 + }, + "authentication": { + "$ref": "/schemas/core/webhook-authentication.json" + } + }, + "required": [ + "url", + "authentication" + ] +} diff --git a/static/schemas/source/index.json b/static/schemas/source/index.json index 0944177caf..2cb6ed00ca 100644 --- a/static/schemas/source/index.json +++ b/static/schemas/source/index.json @@ -696,11 +696,31 @@ "get-content-standards": { "request": { "$ref": "/schemas/content-standards/get-content-standards-request.json", - "description": "Request parameters for retrieving content safety policies" + "description": "Request parameters for retrieving a specific standards configuration" }, "response": { "$ref": "/schemas/content-standards/get-content-standards-response.json", - "description": "Response payload with content safety policies" + "description": "Response payload with full standards configuration including policy and calibration data" + } + }, + "create-content-standards": { + "request": { + "$ref": "/schemas/content-standards/create-content-standards-request.json", + "description": "Request parameters for creating a new content standards configuration" + }, + "response": { + "$ref": "/schemas/content-standards/create-content-standards-response.json", + "description": "Response payload with new standards_id" + } + }, + "update-content-standards": { + "request": { + "$ref": "/schemas/content-standards/update-content-standards-request.json", + "description": "Request parameters for updating an existing content standards configuration" + }, + "response": { + "$ref": "/schemas/content-standards/update-content-standards-response.json", + "description": "Response payload confirming update" } }, "calibrate-content": { From 328a1fd637f6f019f4e03abcdae562bc611ab32f Mon Sep 17 00:00:00 2001 From: Brian O'Kelley Date: Tue, 20 Jan 2026 07:03:19 -0500 Subject: [PATCH 23/34] fix: Convert governance docs to relative links (#820) Absolute links like /docs/governance/... break when docs are synced to v2.6-rc/ on main. Converting to relative links ensures they work in both contexts. Co-authored-by: Claude Opus 4.5 --- docs/governance/brand-standards/index.mdx | 2 +- .../content-standards/artifacts.mdx | 4 +-- docs/governance/content-standards/index.mdx | 26 +++++++++---------- .../tasks/calibrate_content.mdx | 4 +-- .../tasks/create_content_standards.mdx | 10 +++---- .../tasks/delete_content_standards.mdx | 6 ++--- .../tasks/get_content_standards.mdx | 4 +-- .../tasks/get_media_buy_artifacts.mdx | 6 ++--- .../tasks/list_content_standards.mdx | 6 ++--- .../tasks/update_content_standards.mdx | 6 ++--- .../tasks/validate_content_delivery.mdx | 6 ++--- docs/governance/index.mdx | 6 ++--- docs/governance/property/adagents.mdx | 6 ++--- .../property/authorized-properties.mdx | 14 +++++----- docs/governance/property/index.mdx | 16 ++++++------ docs/governance/property/specification.mdx | 8 +++--- docs/governance/property/tasks/index.mdx | 18 ++++++------- .../tasks/validate_property_delivery.mdx | 6 ++--- 18 files changed, 77 insertions(+), 77 deletions(-) diff --git a/docs/governance/brand-standards/index.mdx b/docs/governance/brand-standards/index.mdx index 15a738adc0..16799d37fc 100644 --- a/docs/governance/brand-standards/index.mdx +++ b/docs/governance/brand-standards/index.mdx @@ -87,4 +87,4 @@ Detailed specification and task definitions for Brand Standards governance are u - **Creative compliance**: Validate creatives against brand guidelines - **Audience verification**: Ensure targeting complies with brand audience constraints -See the [Governance Protocol overview](/docs/governance/index) for the broader context of how Brand Standards fits into AdCP governance. +See the [Governance Protocol overview](../index) for the broader context of how Brand Standards fits into AdCP governance. diff --git a/docs/governance/content-standards/artifacts.mdx b/docs/governance/content-standards/artifacts.mdx index 7d2f834a2a..c38a636db0 100644 --- a/docs/governance/content-standards/artifacts.mdx +++ b/docs/governance/content-standards/artifacts.mdx @@ -300,5 +300,5 @@ The verification agent doesn't need to understand the scheme - it's opaque. The ## Related -- [Content Standards Overview](/docs/governance/content-standards) - How artifacts fit into the content standards workflow -- [calibrate_content](/docs/governance/content-standards/tasks/calibrate_content) - Sending artifacts for calibration +- [Content Standards Overview](.) - How artifacts fit into the content standards workflow +- [calibrate_content](./tasks/calibrate_content) - Sending artifacts for calibration diff --git a/docs/governance/content-standards/index.mdx b/docs/governance/content-standards/index.mdx index eda9db83a5..01511d7ed9 100644 --- a/docs/governance/content-standards/index.mdx +++ b/docs/governance/content-standards/index.mdx @@ -43,7 +43,7 @@ This inverts the traditional model. Instead of "send us your content, we'll eval Content standards evaluation involves four key questions that buyers and sellers negotiate: -1. **What content?** - What [artifacts](/docs/governance/content-standards/artifacts) to evaluate (the ad-adjacent content) +1. **What content?** - What [artifacts](./artifacts) to evaluate (the ad-adjacent content) 2. **How much adjacency?** - How many artifacts around the ad slot to consider 3. **What sampling rate?** - What percentage of traffic to evaluate 4. **How to calibrate?** - How to align on policy interpretation before runtime @@ -204,7 +204,7 @@ Content Standards uses **natural language prompts** rather than rigid keyword li The policy prompt enables AI-powered verification agents to understand context and nuance. **Calibration** examples provide a training/test set that helps the agent interpret the policy correctly. -See [Artifacts](/docs/governance/content-standards/artifacts) for details on artifact structure and secured asset access. +See [Artifacts](./artifacts) for details on artifact structure and secured asset access. ## Scoped Standards @@ -255,7 +255,7 @@ Before running campaigns, sellers calibrate their local models against the verif } ``` -See [calibrate_content](/docs/governance/content-standards/tasks/calibrate_content) for the full task specification. +See [calibrate_content](./tasks/calibrate_content) for the full task specification. ## Tasks @@ -263,24 +263,24 @@ See [calibrate_content](/docs/governance/content-standards/tasks/calibrate_conte | Task | Description | |------|-------------| -| [list_content_standards](/docs/governance/content-standards/tasks/list_content_standards) | List available standards configurations | -| [get_content_standards](/docs/governance/content-standards/tasks/get_content_standards) | Retrieve a specific standards configuration | +| [list_content_standards](./tasks/list_content_standards) | List available standards configurations | +| [get_content_standards](./tasks/get_content_standards) | Retrieve a specific standards configuration | ### Management | Task | Description | |------|-------------| -| [create_content_standards](/docs/governance/content-standards/tasks/create_content_standards) | Create a new standards configuration | -| [update_content_standards](/docs/governance/content-standards/tasks/update_content_standards) | Update an existing standards configuration | -| [delete_content_standards](/docs/governance/content-standards/tasks/delete_content_standards) | Delete a standards configuration | +| [create_content_standards](./tasks/create_content_standards) | Create a new standards configuration | +| [update_content_standards](./tasks/update_content_standards) | Update an existing standards configuration | +| [delete_content_standards](./tasks/delete_content_standards) | Delete a standards configuration | ### Calibration & Validation | Task | Description | |------|-------------| -| [calibrate_content](/docs/governance/content-standards/tasks/calibrate_content) | Collaborative dialogue to align on policy interpretation | -| [get_media_buy_artifacts](/docs/governance/content-standards/tasks/get_media_buy_artifacts) | Retrieve content artifacts from a media buy | -| [validate_content_delivery](/docs/governance/content-standards/tasks/validate_content_delivery) | Batch validation of content artifacts | +| [calibrate_content](./tasks/calibrate_content) | Collaborative dialogue to align on policy interpretation | +| [get_media_buy_artifacts](./tasks/get_media_buy_artifacts) | Retrieve content artifacts from a media buy | +| [validate_content_delivery](./tasks/validate_content_delivery) | Batch validation of content artifacts | ## Typical Providers @@ -354,5 +354,5 @@ This architecture aligns with the [IAB Tech Lab ARTF (Agentic RTB Framework)](ht ## Related -- [Artifacts](/docs/governance/content-standards/artifacts) - What artifacts are and how to structure them -- [Brand Manifest](/docs/creative/brand-manifest) - Static brand identity that can link to standards agents +- [Artifacts](./artifacts) - What artifacts are and how to structure them +- [Brand Manifest](../../creative/brand-manifest) - Static brand identity that can link to standards agents diff --git a/docs/governance/content-standards/tasks/calibrate_content.mdx b/docs/governance/content-standards/tasks/calibrate_content.mdx index 801ee3bb53..e30a889ef0 100644 --- a/docs/governance/content-standards/tasks/calibrate_content.mdx +++ b/docs/governance/content-standards/tasks/calibrate_content.mdx @@ -224,5 +224,5 @@ The key insight is that the dialogue happens at the **protocol layer**, not the ## Related Tasks -- [get_content_standards](/docs/governance/content-standards/tasks/get_content_standards) - Retrieve the policies being calibrated against -- [validate_content_delivery](/docs/governance/content-standards/tasks/validate_content_delivery) - Post-campaign delivery validation +- [get_content_standards](./get_content_standards) - Retrieve the policies being calibrated against +- [validate_content_delivery](./validate_content_delivery) - Post-campaign delivery validation diff --git a/docs/governance/content-standards/tasks/create_content_standards.mdx b/docs/governance/content-standards/tasks/create_content_standards.mdx index 51859ca853..3aa9482650 100644 --- a/docs/governance/content-standards/tasks/create_content_standards.mdx +++ b/docs/governance/content-standards/tasks/create_content_standards.mdx @@ -79,12 +79,12 @@ Implementors MUST apply a brand safety floor regardless of what policy is define Multiple standards cannot have overlapping scopes for the same country/channel/language combination. When creating standards that would conflict: -1. **Check existing standards** - Use [list_content_standards](/docs/governance/content-standards/tasks/list_content_standards) filtered by your scope -2. **Update rather than create** - If standards already exist, use [update_content_standards](/docs/governance/content-standards/tasks/update_content_standards) +1. **Check existing standards** - Use [list_content_standards](./list_content_standards) filtered by your scope +2. **Update rather than create** - If standards already exist, use [update_content_standards](./update_content_standards) 3. **Narrow the scope** - Adjust countries or channels to avoid overlap ## Related Tasks -- [list_content_standards](/docs/governance/content-standards/tasks/list_content_standards) - List all configurations -- [update_content_standards](/docs/governance/content-standards/tasks/update_content_standards) - Update a configuration -- [delete_content_standards](/docs/governance/content-standards/tasks/delete_content_standards) - Delete a configuration +- [list_content_standards](./list_content_standards) - List all configurations +- [update_content_standards](./update_content_standards) - Update a configuration +- [delete_content_standards](./delete_content_standards) - Delete a configuration diff --git a/docs/governance/content-standards/tasks/delete_content_standards.mdx b/docs/governance/content-standards/tasks/delete_content_standards.mdx index 2f38244c51..4f0482b964 100644 --- a/docs/governance/content-standards/tasks/delete_content_standards.mdx +++ b/docs/governance/content-standards/tasks/delete_content_standards.mdx @@ -62,9 +62,9 @@ Delete a content standards configuration. } ``` -Standards cannot be deleted while they are referenced by active media buys. Use [list_content_standards](/docs/governance/content-standards/tasks/list_content_standards) to identify usage, or archive standards by setting an expiration date rather than deleting. +Standards cannot be deleted while they are referenced by active media buys. Use [list_content_standards](./list_content_standards) to identify usage, or archive standards by setting an expiration date rather than deleting. ## Related Tasks -- [list_content_standards](/docs/governance/content-standards/tasks/list_content_standards) - List all configurations -- [create_content_standards](/docs/governance/content-standards/tasks/create_content_standards) - Create a new configuration +- [list_content_standards](./list_content_standards) - List all configurations +- [create_content_standards](./create_content_standards) - Create a new configuration diff --git a/docs/governance/content-standards/tasks/get_content_standards.mdx b/docs/governance/content-standards/tasks/get_content_standards.mdx index dec5de452e..5138f2132f 100644 --- a/docs/governance/content-standards/tasks/get_content_standards.mdx +++ b/docs/governance/content-standards/tasks/get_content_standards.mdx @@ -73,5 +73,5 @@ Implementors MUST apply a brand safety floor regardless of what policy is define ## Related Tasks -- [calibrate_content](/docs/governance/content-standards/tasks/calibrate_content) - Collaborative calibration against these standards -- [list_content_standards](/docs/governance/content-standards/tasks/list_content_standards) - List available standards configurations +- [calibrate_content](./calibrate_content) - Collaborative calibration against these standards +- [list_content_standards](./list_content_standards) - List available standards configurations diff --git a/docs/governance/content-standards/tasks/get_media_buy_artifacts.mdx b/docs/governance/content-standards/tasks/get_media_buy_artifacts.mdx index 7b430da991..ca702ddb03 100644 --- a/docs/governance/content-standards/tasks/get_media_buy_artifacts.mdx +++ b/docs/governance/content-standards/tasks/get_media_buy_artifacts.mdx @@ -200,6 +200,6 @@ print(f"False positive rate: {false_positives / len(failures['artifacts']):.1%}" ## Related Tasks -- [validate_content_delivery](/docs/governance/content-standards/tasks/validate_content_delivery) - Validate the artifacts -- [calibrate_content](/docs/governance/content-standards/tasks/calibrate_content) - Understand why artifacts pass/fail -- [get_media_buy_delivery](/docs/media-buy/task-reference/get_media_buy_delivery) - Get performance metrics +- [validate_content_delivery](./validate_content_delivery) - Validate the artifacts +- [calibrate_content](./calibrate_content) - Understand why artifacts pass/fail +- [get_media_buy_delivery](../../../media-buy/task-reference/get_media_buy_delivery) - Get performance metrics diff --git a/docs/governance/content-standards/tasks/list_content_standards.mdx b/docs/governance/content-standards/tasks/list_content_standards.mdx index cdaea651ae..562fe0faf3 100644 --- a/docs/governance/content-standards/tasks/list_content_standards.mdx +++ b/docs/governance/content-standards/tasks/list_content_standards.mdx @@ -23,7 +23,7 @@ List available content standards configurations. **Schema**: [list-content-standards-response.json](https://adcontextprotocol.org/schemas/v2/content-standards/list-content-standards-response.json) -Returns an abbreviated list of standards configurations. Use [get_content_standards](/docs/governance/content-standards/tasks/get_content_standards) to retrieve full details including policy text and calibration data. +Returns an abbreviated list of standards configurations. Use [get_content_standards](./get_content_standards) to retrieve full details including policy text and calibration data. ### Success Response @@ -63,5 +63,5 @@ Returns an abbreviated list of standards configurations. Use [get_content_standa ## Related Tasks -- [get_content_standards](/docs/governance/content-standards/tasks/get_content_standards) - Get a specific standards configuration -- [create_content_standards](/docs/governance/content-standards/tasks/create_content_standards) - Create a new configuration +- [get_content_standards](./get_content_standards) - Get a specific standards configuration +- [create_content_standards](./create_content_standards) - Create a new configuration diff --git a/docs/governance/content-standards/tasks/update_content_standards.mdx b/docs/governance/content-standards/tasks/update_content_standards.mdx index 4f2fb5bc29..67227e7488 100644 --- a/docs/governance/content-standards/tasks/update_content_standards.mdx +++ b/docs/governance/content-standards/tasks/update_content_standards.mdx @@ -67,6 +67,6 @@ Update an existing content standards configuration. Creates a new version. ## Related Tasks -- [get_content_standards](/docs/governance/content-standards/tasks/get_content_standards) - Get current configuration -- [create_content_standards](/docs/governance/content-standards/tasks/create_content_standards) - Create a new configuration -- [delete_content_standards](/docs/governance/content-standards/tasks/delete_content_standards) - Delete a configuration +- [get_content_standards](./get_content_standards) - Get current configuration +- [create_content_standards](./create_content_standards) - Create a new configuration +- [delete_content_standards](./delete_content_standards) - Delete a configuration diff --git a/docs/governance/content-standards/tasks/validate_content_delivery.mdx b/docs/governance/content-standards/tasks/validate_content_delivery.mdx index 97f36c2b71..4dfbdfa91a 100644 --- a/docs/governance/content-standards/tasks/validate_content_delivery.mdx +++ b/docs/governance/content-standards/tasks/validate_content_delivery.mdx @@ -178,6 +178,6 @@ for result in response["results"]: ## Related Tasks -- [get_media_buy_artifacts](/docs/governance/content-standards/tasks/get_media_buy_artifacts) - Get content artifacts from seller -- [calibrate_content](/docs/governance/content-standards/tasks/calibrate_content) - Understand why artifacts pass/fail -- [get_content_standards](/docs/governance/content-standards/tasks/get_content_standards) - Retrieve the policies +- [get_media_buy_artifacts](./get_media_buy_artifacts) - Get content artifacts from seller +- [calibrate_content](./calibrate_content) - Understand why artifacts pass/fail +- [get_content_standards](./get_content_standards) - Retrieve the policies diff --git a/docs/governance/index.mdx b/docs/governance/index.mdx index f08e368f2d..d0f0e2581b 100644 --- a/docs/governance/index.mdx +++ b/docs/governance/index.mdx @@ -19,8 +19,8 @@ The Governance Protocol covers four distinct governance domains: | Domain | What It Governs | Key Mechanisms | |--------|-----------------|----------------| -| **[Property Governance](/docs/governance/property/index)** | Where ads can run | Property lists, compliance filtering, adagents.json authorization | -| **[Brand Standards](/docs/governance/brand-standards/index)** | Brand requirements | Brand manifests, creative guidelines, audience constraints | +| **[Property Governance](./property/index)** | Where ads can run | Property lists, compliance filtering, adagents.json authorization | +| **[Brand Standards](./brand-standards/index)** | Brand requirements | Brand manifests, creative guidelines, audience constraints | | **Creative Governance** | What creatives are compliant | Format validation, content moderation, accessibility | | **Campaign Governance** | What can be bought | Budget controls, approval workflows, policy compliance | @@ -173,7 +173,7 @@ The Media Buy Protocol consumes governance data at multiple stages: 1. Implement feature discovery tasks (`list_property_features`, etc.) 2. Implement stateful list management (CRUD operations) 3. Support webhooks to notify when evaluations change -4. See the [Property Protocol Specification](/docs/governance/property/specification) for detailed implementation guidance +4. See the [Property Protocol Specification](./property/specification) for detailed implementation guidance ## Protocol Sections diff --git a/docs/governance/property/adagents.mdx b/docs/governance/property/adagents.mdx index 2732d1d8f1..ed8b17535c 100644 --- a/docs/governance/property/adagents.mdx +++ b/docs/governance/property/adagents.mdx @@ -620,14 +620,14 @@ The Python library handles validation automatically when fetching - if the adage 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) +1. **Integrate with Product Discovery**: Use [`get_products`](../../media-buy/task-reference/get_products) to discover inventory +2. **Validate at Purchase**: Check authorization before calling [`create_media_buy`](../../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 -- [list_authorized_properties](/docs/media-buy/task-reference/list_authorized_properties) - Discover publisher domains an agent represents +- [list_authorized_properties](../../media-buy/task-reference/list_authorized_properties) - Discover publisher domains an agent represents - [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 diff --git a/docs/governance/property/authorized-properties.mdx b/docs/governance/property/authorized-properties.mdx index 37981ec9e5..bd1e330028 100644 --- a/docs/governance/property/authorized-properties.mdx +++ b/docs/governance/property/authorized-properties.mdx @@ -93,7 +93,7 @@ Publishers authorize sales agents by hosting an `adagents.json` file at `/.well- ## How Sales Agents Share Authorized Properties -Sales agents use the [`list_authorized_properties`](/docs/media-buy/task-reference/list_authorized_properties) task to declare all properties they are authorized to represent. This serves multiple purposes: +Sales agents use the [`list_authorized_properties`](../../media-buy/task-reference/list_authorized_properties) task to declare all properties they are authorized to represent. This serves multiple purposes: 1. **Transparency**: Buyers can see what properties an agent represents 2. **Validation enablement**: Provides the data buyers need to verify authorization @@ -248,9 +248,9 @@ if (!authorized) { ## Integration with Product Discovery -Authorization validation integrates seamlessly with [Product Discovery](/docs/media-buy/product-discovery/): +Authorization validation integrates seamlessly with [Product Discovery](../../media-buy/product-discovery/): -1. **Discover products** using [`get_products`](/docs/media-buy/task-reference/get_products) +1. **Discover products** using [`get_products`](../../media-buy/task-reference/get_products) 2. **Validate authorization** for properties referenced in products 3. **Proceed confidently** with authorized inventory 4. **Flag unauthorized** products for manual review @@ -269,11 +269,11 @@ For complete technical details on implementing the `adagents.json` file format, - Validation code examples and error handling - Security considerations and best practices -See the **[adagents.json Tech Spec](/docs/governance/property/adagents)** for complete implementation guidance. +See the **[adagents.json Tech Spec](./adagents)** for complete implementation guidance. ## Related Documentation -- **[`list_authorized_properties`](/docs/media-buy/task-reference/list_authorized_properties)** - API reference for property discovery -- **[Product Discovery](/docs/media-buy/product-discovery/)** - How authorization integrates with product discovery +- **[`list_authorized_properties`](../../media-buy/task-reference/list_authorized_properties)** - API reference for property discovery +- **[Product Discovery](../../media-buy/product-discovery/)** - How authorization integrates with product discovery - **[Properties Schema](https://adcontextprotocol.org/schemas/v2/core/property.json)** - Technical property data model -- **[adagents.json Tech Spec](/docs/governance/property/adagents)** - Complete `adagents.json` implementation guide \ No newline at end of file +- **[adagents.json Tech Spec](./adagents)** - Complete `adagents.json` implementation guide \ No newline at end of file diff --git a/docs/governance/property/index.mdx b/docs/governance/property/index.mdx index d4f8468777..8bff63f4e6 100644 --- a/docs/governance/property/index.mdx +++ b/docs/governance/property/index.mdx @@ -48,7 +48,7 @@ Publishers declare their properties and authorize sales agents via `/.well-known } ``` -See the [adagents.json Tech Spec](/docs/governance/property/adagents) for complete documentation. +See the [adagents.json Tech Spec](./adagents) for complete documentation. ## Buyer Side: Property Data and Selection @@ -197,14 +197,14 @@ Both protocols operate on properties but serve different purposes: ### Discovery -- **[list_property_features](/docs/governance/property/tasks/list_property_features)**: Discover what data a governance agent can provide about properties +- **[list_property_features](./tasks/list_property_features)**: Discover what data a governance agent can provide about properties ### Property List Management -- **[create_property_list](/docs/governance/property/tasks/property_lists#create_property_list)**: Create a new property list on a governance agent -- **[get_property_list](/docs/governance/property/tasks/property_lists#get_property_list)**: Retrieve resolved properties (with caching guidance) -- **[update_property_list](/docs/governance/property/tasks/property_lists#update_property_list)**: Modify filters or base properties -- **[delete_property_list](/docs/governance/property/tasks/property_lists#delete_property_list)**: Remove a property list +- **[create_property_list](./tasks/property_lists#create_property_list)**: Create a new property list on a governance agent +- **[get_property_list](./tasks/property_lists#get_property_list)**: Retrieve resolved properties (with caching guidance) +- **[update_property_list](./tasks/property_lists#update_property_list)**: Modify filters or base properties +- **[delete_property_list](./tasks/property_lists#delete_property_list)**: Remove a property list ## Getting Started @@ -222,6 +222,6 @@ Both protocols operate on properties but serve different purposes: 1. Implement `list_property_features` to advertise your capabilities 2. Implement property list CRUD operations 3. Support webhooks to notify buyers when evaluations change -4. See the [Protocol Specification](/docs/governance/property/specification) for implementation details +4. See the [Protocol Specification](./specification) for implementation details -See the [Protocol Specification](/docs/governance/property/specification) for detailed implementation guidance. +See the [Protocol Specification](./specification) for detailed implementation guidance. diff --git a/docs/governance/property/specification.mdx b/docs/governance/property/specification.mdx index 343d1c7e32..f27ef564fd 100644 --- a/docs/governance/property/specification.mdx +++ b/docs/governance/property/specification.mdx @@ -605,7 +605,7 @@ Media buys can reference governance policies via property list references: ## Next Steps -- See the [adagents.json Tech Spec](/docs/governance/property/adagents) for property declaration and authorization -- See the [list_property_features task reference](/docs/governance/property/tasks/list_property_features) for capability discovery -- See the [Property List Management](/docs/governance/property/tasks/property_lists) for CRUD operations and webhooks -- See the [validate_property_delivery task reference](/docs/governance/property/tasks/validate_property_delivery) for post-campaign compliance validation +- See the [adagents.json Tech Spec](./adagents) for property declaration and authorization +- See the [list_property_features task reference](./tasks/list_property_features) for capability discovery +- See the [Property List Management](./tasks/property_lists) for CRUD operations and webhooks +- See the [validate_property_delivery task reference](./tasks/validate_property_delivery) for post-campaign compliance validation diff --git a/docs/governance/property/tasks/index.mdx b/docs/governance/property/tasks/index.mdx index 4679e3704b..5b65fc4364 100644 --- a/docs/governance/property/tasks/index.mdx +++ b/docs/governance/property/tasks/index.mdx @@ -15,27 +15,27 @@ Property governance uses a **stateful** model where all evaluation happens throu | Task | Purpose | Response Time | |------|---------|---------------| -| [list_property_features](/docs/governance/property/tasks/list_property_features) | Discover agent capabilities | ~200ms | +| [list_property_features](./list_property_features) | Discover agent capabilities | ~200ms | ## Property List Management | Task | Purpose | Response Time | |------|---------|---------------| -| [create_property_list](/docs/governance/property/tasks/property_lists#create_property_list) | Create a new property list | ~500ms | -| [update_property_list](/docs/governance/property/tasks/property_lists#update_property_list) | Modify an existing list | ~500ms | -| [get_property_list](/docs/governance/property/tasks/property_lists#get_property_list) | Retrieve list with resolved properties | ~2-5s | -| [list_property_lists](/docs/governance/property/tasks/property_lists#list_property_lists) | List all property lists | ~500ms | -| [delete_property_list](/docs/governance/property/tasks/property_lists#delete_property_list) | Delete a property list | ~200ms | +| [create_property_list](./property_lists#create_property_list) | Create a new property list | ~500ms | +| [update_property_list](./property_lists#update_property_list) | Modify an existing list | ~500ms | +| [get_property_list](./property_lists#get_property_list) | Retrieve list with resolved properties | ~2-5s | +| [list_property_lists](./property_lists#list_property_lists) | List all property lists | ~500ms | +| [delete_property_list](./property_lists#delete_property_list) | Delete a property list | ~200ms | -See [Property List Management](/docs/governance/property/tasks/property_lists) for complete CRUD documentation. +See [Property List Management](./property_lists) for complete CRUD documentation. ## Validation | Task | Purpose | Response Time | |------|---------|---------------| -| [validate_property_delivery](/docs/governance/property/tasks/validate_property_delivery) | Validate delivery records against a list | ~1-5s | +| [validate_property_delivery](./validate_property_delivery) | Validate delivery records against a list | ~1-5s | -See [validate_property_delivery](/docs/governance/property/tasks/validate_property_delivery) for post-campaign compliance validation. +See [validate_property_delivery](./validate_property_delivery) for post-campaign compliance validation. ## Task Selection Guide diff --git a/docs/governance/property/tasks/validate_property_delivery.mdx b/docs/governance/property/tasks/validate_property_delivery.mdx index 7f9acc8c42..1e0fe14594 100644 --- a/docs/governance/property/tasks/validate_property_delivery.mdx +++ b/docs/governance/property/tasks/validate_property_delivery.mdx @@ -397,6 +397,6 @@ def analyze_validation(response): ## Related Tasks -- [create_property_list](/docs/governance/property/tasks/property_lists#create_property_list) - Create the list to validate against -- [get_property_list](/docs/governance/property/tasks/property_lists#get_property_list) - Retrieve current list membership -- [list_property_features](/docs/governance/property/tasks/list_property_features) - Discover available filter features +- [create_property_list](./property_lists#create_property_list) - Create the list to validate against +- [get_property_list](./property_lists#get_property_list) - Retrieve current list membership +- [list_property_features](./list_property_features) - Discover available filter features From 533b6ab76e6308987bc6aa84bf75c1150570b32a Mon Sep 17 00:00:00 2001 From: Brian O'Kelley Date: Tue, 20 Jan 2026 16:21:12 -0500 Subject: [PATCH 24/34] fix: Mintlify callout syntax and case-insensitivity docs (#834) - Convert `:::note` Docusaurus syntax to Mintlify `` components - Add case-insensitivity documentation for country codes (ISO 3166-1 alpha-2) and language codes (ISO 639-1/BCP 47) - Document recommended formats (uppercase for countries, lowercase for languages) - Remove orphaned webhook-config.json and webhook-authentication.json schemas that were never referenced Co-authored-by: Claude Opus 4.5 --- .changeset/content-standards-fixes.md | 9 ++++++ docs/governance/content-standards/index.mdx | 11 +++++++- .../tasks/create_content_standards.mdx | 6 ++-- .../tasks/get_content_standards.mdx | 10 ++++--- .../tasks/list_content_standards.mdx | 4 +-- docs/governance/property/specification.mdx | 2 +- .../property/tasks/property_lists.mdx | 4 +-- .../media-buy/task-reference/get_products.mdx | 2 +- .../list_authorized_properties.mdx | 2 +- docs/reference/signals-quick-reference.mdx | 2 +- docs/signals/tasks/get_signals.mdx | 2 +- .../source/core/webhook-authentication.json | 28 ------------------- .../schemas/source/core/webhook-config.json | 26 ----------------- 13 files changed, 38 insertions(+), 70 deletions(-) create mode 100644 .changeset/content-standards-fixes.md delete mode 100644 static/schemas/source/core/webhook-authentication.json delete mode 100644 static/schemas/source/core/webhook-config.json diff --git a/.changeset/content-standards-fixes.md b/.changeset/content-standards-fixes.md new file mode 100644 index 0000000000..5ad3b4e16d --- /dev/null +++ b/.changeset/content-standards-fixes.md @@ -0,0 +1,9 @@ +--- +"adcontextprotocol": patch +--- + +Fix Mintlify callout syntax and add case-insensitivity notes for country/language codes + +- Convert `:::note` Docusaurus syntax to Mintlify `` components +- Add case-insensitivity documentation for country codes (ISO 3166-1 alpha-2) and language codes (ISO 639-1/BCP 47) +- Remove orphaned webhook-config.json and webhook-authentication.json schemas diff --git a/docs/governance/content-standards/index.mdx b/docs/governance/content-standards/index.mdx index 01511d7ed9..32929e96c1 100644 --- a/docs/governance/content-standards/index.mdx +++ b/docs/governance/content-standards/index.mdx @@ -215,10 +215,19 @@ Buyers typically maintain multiple standards configurations for different contex "standards_id": "uk_tv_zero_calorie", "name": "UK TV - zero-calorie brands", "countries_all": ["GB"], - "channels_any": ["ctv", "linear_tv"] + "channels_any": ["ctv", "linear_tv"], + "languages_any": ["en"] } ``` + +**Code Format Conventions** + +Country and language codes are **case-insensitive** - implementations must normalize before comparison. Recommended formats follow ISO standards: +- **Countries**: Uppercase ISO 3166-1 alpha-2 (e.g., `GB`, `US`, `DE`) +- **Languages**: Lowercase ISO 639-1 or BCP 47 (e.g., `en`, `de`, `fr`) + + **The buyer selects the appropriate `standards_id` when creating a media buy.** The seller receives a reference to the resolved standards - they don't need to do scope matching themselves. ## Calibration diff --git a/docs/governance/content-standards/tasks/create_content_standards.mdx b/docs/governance/content-standards/tasks/create_content_standards.mdx index 3aa9482650..f3f2b729b4 100644 --- a/docs/governance/content-standards/tasks/create_content_standards.mdx +++ b/docs/governance/content-standards/tasks/create_content_standards.mdx @@ -19,9 +19,11 @@ Create a new content standards configuration. | `policy` | string | Yes | Natural language policy prompt | | `calibration_exemplars` | object | No | Training set of pass/fail artifacts for calibration | -:::note[Brand Safety Floor Requirement] + +**Brand Safety Floor Requirement** + Implementors MUST apply a brand safety floor regardless of what policy is defined in content standards. Content that violates the floor (hate speech, illegal content, etc.) must be excluded even when no content standards are specified. AdCP does not define the floor specification; this is left to implementors and industry standards (e.g., GARM categories). -::: + ### Example Request diff --git a/docs/governance/content-standards/tasks/get_content_standards.mdx b/docs/governance/content-standards/tasks/get_content_standards.mdx index 5138f2132f..409dd34798 100644 --- a/docs/governance/content-standards/tasks/get_content_standards.mdx +++ b/docs/governance/content-standards/tasks/get_content_standards.mdx @@ -48,15 +48,17 @@ Retrieve content safety policies for a specific standards configuration. |-------|-------------| | `standards_id` | Unique identifier for this standards configuration | | `name` | Human-readable name | -| `countries_all` | ISO country codes - standards apply in ALL listed countries | +| `countries_all` | ISO 3166-1 alpha-2 country codes (case-insensitive, uppercase recommended) - standards apply in ALL listed countries | | `channels_any` | Ad channels - standards apply to ANY of the listed channels | -| `languages_any` | BCP 47 language tags - standards apply to content in ANY of these languages | +| `languages_any` | ISO 639-1 or BCP 47 language tags (case-insensitive, lowercase recommended) - standards apply to content in ANY of these languages | | `policy` | Natural language policy describing acceptable and unacceptable content contexts | | `calibration_exemplars` | Training/test set of content contexts (pass/fail) to calibrate policy interpretation | -:::note[Brand Safety Floor Requirement] + +**Brand Safety Floor Requirement** + Implementors MUST apply a brand safety floor regardless of what policy is defined. AdCP does not define the floor specification. -::: + ### Error Response diff --git a/docs/governance/content-standards/tasks/list_content_standards.mdx b/docs/governance/content-standards/tasks/list_content_standards.mdx index 562fe0faf3..3110272a68 100644 --- a/docs/governance/content-standards/tasks/list_content_standards.mdx +++ b/docs/governance/content-standards/tasks/list_content_standards.mdx @@ -15,9 +15,9 @@ List available content standards configurations. | Parameter | Type | Required | Description | |-----------|------|----------|-------------| -| `countries` | array | No | Filter by country codes | +| `countries` | array | No | Filter by ISO 3166-1 alpha-2 country codes (case-insensitive) | | `channels` | array | No | Filter by channels | -| `languages` | array | No | Filter by BCP 47 language tags | +| `languages` | array | No | Filter by ISO 639-1 or BCP 47 language tags (case-insensitive) | ## Response diff --git a/docs/governance/property/specification.mdx b/docs/governance/property/specification.mdx index f27ef564fd..0d3e3e119c 100644 --- a/docs/governance/property/specification.mdx +++ b/docs/governance/property/specification.mdx @@ -192,7 +192,7 @@ Discover what features a governance agent can evaluate. Create a new property list with filters and optional brand manifest. **Required Parameters**: -- At least one country in `countries_all` (ISO country code) +- At least one country in `countries_all` (ISO 3166-1 alpha-2 code, case-insensitive) - At least one channel in `channels_any` (display, video, audio, etc.) **Base Properties**: An array of property sources to evaluate. Each entry is a discriminated union with `selection_type` as the discriminator: diff --git a/docs/governance/property/tasks/property_lists.mdx b/docs/governance/property/tasks/property_lists.mdx index a46e54545f..4faef62b2c 100644 --- a/docs/governance/property/tasks/property_lists.mdx +++ b/docs/governance/property/tasks/property_lists.mdx @@ -168,7 +168,7 @@ Filters are applied when the list is resolved (via `get_property_list`): | Filter | Type | Description | |--------|------|-------------| -| `countries_all` | string[] | ISO country codes - property must have feature data for ALL (required) | +| `countries_all` | string[] | ISO 3166-1 alpha-2 country codes (case-insensitive, uppercase recommended) - property must have feature data for ALL (required) | | `channels_any` | string[] | Advertising channels - property must support ANY (required) | | `property_types` | string[] | Property types (website, mobile_app, ctv_app, etc.) | | `feature_requirements` | FeatureRequirement[] | Requirements based on agent-provided features | @@ -229,7 +229,7 @@ This transparency helps agencies distinguish between properties that passed a re ### Required Filters Every property list must include at least: -- One country in `countries_all` (ISO country code) +- One country in `countries_all` (ISO 3166-1 alpha-2 code, case-insensitive) - One channel in `channels_any` (display, video, audio, etc.) These are required because governance agents need to know which jurisdiction and context to evaluate properties against. diff --git a/docs/media-buy/task-reference/get_products.mdx b/docs/media-buy/task-reference/get_products.mdx index fa00a940b7..5b1835d45e 100644 --- a/docs/media-buy/task-reference/get_products.mdx +++ b/docs/media-buy/task-reference/get_products.mdx @@ -144,7 +144,7 @@ asyncio.run(discover_with_filters()) | `start_date` | string | Campaign start date in ISO 8601 format (YYYY-MM-DD) for availability checks | | `end_date` | string | Campaign end date in ISO 8601 format (YYYY-MM-DD) for availability checks | | `budget_range` | object | Budget range to filter appropriate products (see Budget Range Object below) | -| `countries` | string[] | Filter by target countries using ISO 3166-1 alpha-2 codes (e.g., `["US", "CA", "GB"]`) | +| `countries` | string[] | Filter by target countries using ISO 3166-1 alpha-2 codes (case-insensitive, e.g., `["US", "CA", "GB"]`) | | `channels` | string[] | Filter by advertising channels (e.g., `["display", "video", "dooh", "ctv", "audio", "native"]`) | ### Budget Range Object diff --git a/docs/media-buy/task-reference/list_authorized_properties.mdx b/docs/media-buy/task-reference/list_authorized_properties.mdx index 55bd3fcf87..7f6b98d0b7 100644 --- a/docs/media-buy/task-reference/list_authorized_properties.mdx +++ b/docs/media-buy/task-reference/list_authorized_properties.mdx @@ -29,7 +29,7 @@ Discover which publishers a sales agent is authorized to represent. Returns publ |-------|-------------| | `publisher_domains` | Array of publisher domains this agent represents | | `primary_channels` | Optional main advertising channels (ctv, display, video, audio, dooh, etc.) | -| `primary_countries` | Optional main countries (ISO 3166-1 alpha-2 codes) | +| `primary_countries` | Optional main countries (ISO 3166-1 alpha-2 codes, case-insensitive) | | `portfolio_description` | Optional markdown description of portfolio and capabilities | | `last_updated` | Optional ISO 8601 timestamp of last publisher list update | diff --git a/docs/reference/signals-quick-reference.mdx b/docs/reference/signals-quick-reference.mdx index 084b7bd974..a3f068c81b 100644 --- a/docs/reference/signals-quick-reference.mdx +++ b/docs/reference/signals-quick-reference.mdx @@ -53,7 +53,7 @@ Discover signals based on natural language description, with deployment status a - `signal_spec` (string, required): Natural language description of desired signals - `deliver_to` (object, required): Where signals will be used - `deployments` (array): Target platforms/agents with `type`, `platform`/`agent_url`, and optional `account` - - `countries` (array): ISO country codes where signals will be used + - `countries` (array): ISO 3166-1 alpha-2 country codes where signals will be used (case-insensitive, uppercase recommended) - `filters` (object, optional): Filter by `catalog_types`, `data_providers`, `max_cpm`, `min_coverage_percentage` - `max_results` (number, optional): Limit number of results diff --git a/docs/signals/tasks/get_signals.mdx b/docs/signals/tasks/get_signals.mdx index 74d9e8be85..972f8571de 100644 --- a/docs/signals/tasks/get_signals.mdx +++ b/docs/signals/tasks/get_signals.mdx @@ -27,7 +27,7 @@ The `get_signals` task returns both signal metadata and real-time deployment sta | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `deployments` | Destination[] | Yes | List of deployment targets (DSPs, sales agents, etc.) - see Destination Object below | -| `countries` | string[] | Yes | Countries where signals will be used (ISO codes) | +| `countries` | string[] | Yes | Countries where signals will be used (ISO 3166-1 alpha-2 codes, case-insensitive, uppercase recommended) | ### Destination Object diff --git a/static/schemas/source/core/webhook-authentication.json b/static/schemas/source/core/webhook-authentication.json deleted file mode 100644 index 504b2e3804..0000000000 --- a/static/schemas/source/core/webhook-authentication.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/core/webhook-authentication.json", - "title": "Webhook Authentication", - "description": "Authentication configuration for webhook delivery. Supports Bearer tokens for simple authentication or HMAC-SHA256 for signature-based verification (recommended for production). Compatible with A2A PushNotificationConfig structure.", - "type": "object", - "properties": { - "schemes": { - "type": "array", - "description": "Array of authentication schemes. Supported: ['Bearer'] for simple token auth, ['HMAC-SHA256'] for signature verification (recommended for production)", - "items": { - "$ref": "/schemas/enums/auth-scheme.json" - }, - "minItems": 1, - "maxItems": 1 - }, - "credentials": { - "type": "string", - "description": "Credentials for authentication. For Bearer: token sent in Authorization header. For HMAC-SHA256: shared secret used to generate signature. Minimum 32 characters. Exchanged out-of-band during onboarding.", - "minLength": 32 - } - }, - "required": [ - "schemes", - "credentials" - ], - "additionalProperties": false -} diff --git a/static/schemas/source/core/webhook-config.json b/static/schemas/source/core/webhook-config.json deleted file mode 100644 index 0d1fe097a2..0000000000 --- a/static/schemas/source/core/webhook-config.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/core/webhook-config.json", - "title": "Webhook Config", - "description": "Base webhook configuration for authenticated HTTP callbacks. Defines the common structure for url, token, and authentication used by reporting_webhook, artifact_webhook, and other webhook configurations. Note: Due to JSON Schema limitations with allOf + additionalProperties:false, consuming schemas inline these properties rather than using $ref composition.", - "type": "object", - "properties": { - "url": { - "type": "string", - "format": "uri", - "description": "Webhook endpoint URL" - }, - "token": { - "type": "string", - "description": "Optional client-provided token for webhook validation. Echoed back in webhook payload to validate request authenticity.", - "minLength": 16 - }, - "authentication": { - "$ref": "/schemas/core/webhook-authentication.json" - } - }, - "required": [ - "url", - "authentication" - ] -} From b6b090d412446b994e292abda7150c688f9e5a52 Mon Sep 17 00:00:00 2001 From: Brian O'Kelley Date: Thu, 22 Jan 2026 11:30:34 -0500 Subject: [PATCH 25/34] fix: Remove redundant singular filter fields from creative-filters schema (#845) BREAKING CHANGE: Removed `format`, `status`, and `assigned_to_package` fields. Use array versions instead: `formats`, `statuses`, `assigned_to_packages`. Arrays with one item work identically to the removed singular fields. Co-authored-by: Claude Opus 4.5 --- .changeset/simplify-filters.md | 3 ++ .../task-reference/list_creatives.mdx | 31 +++++++++---------- .../schemas/source/core/creative-filters.json | 16 ++-------- .../task-reference/list_creatives.mdx | 31 +++++++++---------- 4 files changed, 33 insertions(+), 48 deletions(-) create mode 100644 .changeset/simplify-filters.md diff --git a/.changeset/simplify-filters.md b/.changeset/simplify-filters.md new file mode 100644 index 0000000000..ec380ec43f --- /dev/null +++ b/.changeset/simplify-filters.md @@ -0,0 +1,3 @@ +--- +--- + diff --git a/docs/media-buy/task-reference/list_creatives.mdx b/docs/media-buy/task-reference/list_creatives.mdx index 1f5c3804de..6ba0951f9a 100644 --- a/docs/media-buy/task-reference/list_creatives.mdx +++ b/docs/media-buy/task-reference/list_creatives.mdx @@ -46,10 +46,8 @@ The `list_creatives` task provides comprehensive search and filtering capabiliti ```json { "filters": { - "format": "video", // Single format - "formats": ["video", "audio"], // Multiple formats - "status": "approved", // Single status - "statuses": ["approved", "pending_review"] // Multiple statuses + "formats": ["video"], // Filter by format types + "statuses": ["approved", "pending_review"] // Filter by statuses } } ``` @@ -94,8 +92,7 @@ The `list_creatives` task provides comprehensive search and filtering capabiliti ```json { "filters": { - "assigned_to_package": "pkg_ctv_001", // Assigned to specific package - "assigned_to_packages": ["pkg_001", "pkg_002"], // Assigned to any of these packages + "assigned_to_packages": ["pkg_ctv_001"], // Assigned to any of these packages "media_buy_ids": ["mb_123", "mb_456"], // Assigned to any of these media buys "buyer_refs": ["campaign_abc", "campaign_xyz"], // Assigned to media buys with these buyer references "unassigned": true // Unassigned creatives only @@ -206,8 +203,8 @@ List all approved video creatives: ```json { "filters": { - "format": "video", - "status": "approved" + "formats": ["video"], + "statuses": ["approved"] }, "sort": { "field": "created_date", @@ -246,7 +243,7 @@ Get creatives ready for assignment to new campaigns: { "filters": { "unassigned": true, - "status": "approved" + "statuses": ["approved"] }, "sort": { "field": "created_date", @@ -265,7 +262,7 @@ Find all creatives assigned to a specific package: ```json { "filters": { - "assigned_to_package": "pkg_ctv_premium_001" + "assigned_to_packages": ["pkg_ctv_premium_001"] }, "include_assignments": true, "include_performance": true, @@ -285,7 +282,7 @@ Find mobile-optimized creatives across multiple formats: "filters": { "formats": ["display_320x50", "video_9x16_mobile", "display_300x250"], "tags_any": ["mobile_optimized", "responsive"], - "status": "approved" + "statuses": ["approved"] }, "sort": { "field": "updated_date", @@ -303,7 +300,7 @@ Get minimal creative data for UI dropdown: "fields": ["creative_id", "name", "format", "status"], "include_assignments": false, "filters": { - "status": "approved" + "statuses": ["approved"] }, "sort": { "field": "name", @@ -358,7 +355,7 @@ Find all creatives used in specific media buys or campaigns: { "filters": { "media_buy_ids": ["mb_summer_2025", "mb_spring_2025"], - "status": "approved" + "statuses": ["approved"] }, "include_assignments": true, "include_performance": true, @@ -429,7 +426,7 @@ Search creatives across related campaigns by buyer reference: ```json { "filters": { - "status": "approved", + "statuses": ["approved"], "unassigned": true }, "sort": { "field": "created_date", "direction": "desc" } @@ -502,7 +499,7 @@ For queries returning very large result sets: // Get lightweight creative list for dropdown const response = await adcp.list_creatives({ fields: ["creative_id", "name", "format"], - filters: { status: "approved" }, + filters: { statuses: ["approved"] }, sort: { field: "name", direction: "asc" }, include_assignments: false }); @@ -525,12 +522,12 @@ const response = await adcp.list_creatives({ ### Assignment Management -```javascript +```javascript // Find unassigned creatives ready for new campaigns const response = await adcp.list_creatives({ filters: { unassigned: true, - status: "approved", + statuses: ["approved"], formats: ["video", "display"] }, sort: { field: "created_date", direction: "desc" } diff --git a/static/schemas/source/core/creative-filters.json b/static/schemas/source/core/creative-filters.json index ce9cee5a74..75f5c5c962 100644 --- a/static/schemas/source/core/creative-filters.json +++ b/static/schemas/source/core/creative-filters.json @@ -5,24 +5,16 @@ "description": "Filter criteria for querying creative assets from the centralized library", "type": "object", "properties": { - "format": { - "type": "string", - "description": "Filter by creative format type (e.g., video, audio, display)" - }, "formats": { "type": "array", - "description": "Filter by multiple creative format types", + "description": "Filter by creative format types (e.g., video, audio, display)", "items": { "type": "string" } }, - "status": { - "$ref": "/schemas/enums/creative-status.json", - "description": "Filter by creative approval status" - }, "statuses": { "type": "array", - "description": "Filter by multiple creative statuses", + "description": "Filter by creative approval statuses", "items": { "$ref": "/schemas/enums/creative-status.json" } @@ -73,10 +65,6 @@ "format": "date-time", "description": "Filter creatives last updated before this date (ISO 8601)" }, - "assigned_to_package": { - "type": "string", - "description": "Filter creatives assigned to this specific package" - }, "assigned_to_packages": { "type": "array", "description": "Filter creatives assigned to any of these packages", diff --git a/v2.6-rc/docs/media-buy/task-reference/list_creatives.mdx b/v2.6-rc/docs/media-buy/task-reference/list_creatives.mdx index 1f5c3804de..6ba0951f9a 100644 --- a/v2.6-rc/docs/media-buy/task-reference/list_creatives.mdx +++ b/v2.6-rc/docs/media-buy/task-reference/list_creatives.mdx @@ -46,10 +46,8 @@ The `list_creatives` task provides comprehensive search and filtering capabiliti ```json { "filters": { - "format": "video", // Single format - "formats": ["video", "audio"], // Multiple formats - "status": "approved", // Single status - "statuses": ["approved", "pending_review"] // Multiple statuses + "formats": ["video"], // Filter by format types + "statuses": ["approved", "pending_review"] // Filter by statuses } } ``` @@ -94,8 +92,7 @@ The `list_creatives` task provides comprehensive search and filtering capabiliti ```json { "filters": { - "assigned_to_package": "pkg_ctv_001", // Assigned to specific package - "assigned_to_packages": ["pkg_001", "pkg_002"], // Assigned to any of these packages + "assigned_to_packages": ["pkg_ctv_001"], // Assigned to any of these packages "media_buy_ids": ["mb_123", "mb_456"], // Assigned to any of these media buys "buyer_refs": ["campaign_abc", "campaign_xyz"], // Assigned to media buys with these buyer references "unassigned": true // Unassigned creatives only @@ -206,8 +203,8 @@ List all approved video creatives: ```json { "filters": { - "format": "video", - "status": "approved" + "formats": ["video"], + "statuses": ["approved"] }, "sort": { "field": "created_date", @@ -246,7 +243,7 @@ Get creatives ready for assignment to new campaigns: { "filters": { "unassigned": true, - "status": "approved" + "statuses": ["approved"] }, "sort": { "field": "created_date", @@ -265,7 +262,7 @@ Find all creatives assigned to a specific package: ```json { "filters": { - "assigned_to_package": "pkg_ctv_premium_001" + "assigned_to_packages": ["pkg_ctv_premium_001"] }, "include_assignments": true, "include_performance": true, @@ -285,7 +282,7 @@ Find mobile-optimized creatives across multiple formats: "filters": { "formats": ["display_320x50", "video_9x16_mobile", "display_300x250"], "tags_any": ["mobile_optimized", "responsive"], - "status": "approved" + "statuses": ["approved"] }, "sort": { "field": "updated_date", @@ -303,7 +300,7 @@ Get minimal creative data for UI dropdown: "fields": ["creative_id", "name", "format", "status"], "include_assignments": false, "filters": { - "status": "approved" + "statuses": ["approved"] }, "sort": { "field": "name", @@ -358,7 +355,7 @@ Find all creatives used in specific media buys or campaigns: { "filters": { "media_buy_ids": ["mb_summer_2025", "mb_spring_2025"], - "status": "approved" + "statuses": ["approved"] }, "include_assignments": true, "include_performance": true, @@ -429,7 +426,7 @@ Search creatives across related campaigns by buyer reference: ```json { "filters": { - "status": "approved", + "statuses": ["approved"], "unassigned": true }, "sort": { "field": "created_date", "direction": "desc" } @@ -502,7 +499,7 @@ For queries returning very large result sets: // Get lightweight creative list for dropdown const response = await adcp.list_creatives({ fields: ["creative_id", "name", "format"], - filters: { status: "approved" }, + filters: { statuses: ["approved"] }, sort: { field: "name", direction: "asc" }, include_assignments: false }); @@ -525,12 +522,12 @@ const response = await adcp.list_creatives({ ### Assignment Management -```javascript +```javascript // Find unassigned creatives ready for new campaigns const response = await adcp.list_creatives({ filters: { unassigned: true, - status: "approved", + statuses: ["approved"], formats: ["video", "display"] }, sort: { field: "created_date", direction: "desc" } From e466ece6dd1b3a5356828e5e6dd1b29782c6c763 Mon Sep 17 00:00:00 2001 From: Brian O'Kelley Date: Fri, 23 Jan 2026 10:37:05 -0500 Subject: [PATCH 26/34] feat: Add 'archived' status to creative-status enum (#847) * feat: Add 'archived' status to creative-status enum - Add 'archived' to creative-status.json enum - Document default exclusion behavior in creative-filters.json - Update list_creatives docs with archived filtering examples - Add 'processing' to status_summary schema for completeness - Update data-models.mdx TypeScript types Co-Authored-By: Claude Opus 4.5 * fix: Remove erroneous status field from assignment response Assignments are binary - they exist or they don't. The package/media buy status determines delivery, not the assignment itself. Co-Authored-By: Claude Opus 4.5 * fix: Replace approved boolean with status enum in creative-asset Use the same status field for both input (sync_creatives) and output (list_creatives) for consistency. The status enum values are: - approved: finalize generative creative - rejected: request regeneration - processing, pending_review, archived: system-set states Co-Authored-By: Claude Opus 4.5 * fix: Rename package_name to buyer_ref in assignment response Package schema has buyer_ref, not name. Updated assignment response to match. Co-Authored-By: Claude Opus 4.5 --------- Co-authored-by: Claude Opus 4.5 --- .changeset/whole-sides-join.md | 4 +++ .../task-reference/list_creatives.mdx | 23 +++++++++++++++- docs/reference/data-models.mdx | 4 +-- .../schemas/source/core/creative-asset.json | 6 ++--- .../schemas/source/core/creative-filters.json | 2 +- .../schemas/source/enums/creative-status.json | 6 +++-- .../media-buy/list-creatives-response.json | 26 +++++++------------ .../task-reference/list_creatives.mdx | 23 +++++++++++++++- v2.6-rc/docs/reference/data-models.mdx | 4 +-- 9 files changed, 70 insertions(+), 28 deletions(-) create mode 100644 .changeset/whole-sides-join.md diff --git a/.changeset/whole-sides-join.md b/.changeset/whole-sides-join.md new file mode 100644 index 0000000000..3c74f7163d --- /dev/null +++ b/.changeset/whole-sides-join.md @@ -0,0 +1,4 @@ +--- +--- + +Add 'archived' status to creative-status enum and document default exclusion behavior in list_creatives. Remove erroneous status field from assignment response (assignments are binary - they exist or don't). Replace approved boolean with status enum in creative-asset.json for consistency. Rename package_name to buyer_ref in assignment response to match package schema. diff --git a/docs/media-buy/task-reference/list_creatives.mdx b/docs/media-buy/task-reference/list_creatives.mdx index 6ba0951f9a..46e76a9d7d 100644 --- a/docs/media-buy/task-reference/list_creatives.mdx +++ b/docs/media-buy/task-reference/list_creatives.mdx @@ -52,6 +52,10 @@ The `list_creatives` task provides comprehensive search and filtering capabiliti } ``` + +**Archived creatives are excluded by default.** To include archived creatives in results, explicitly filter by `status: "archived"` or include `"archived"` in the `statuses` array. + + ### Tag-Based Filtering ```json @@ -189,7 +193,8 @@ The response provides comprehensive creative data with optional enrichment: "status_summary": { "approved": 20, "pending_review": 3, - "rejected": 2 + "rejected": 2, + "archived": 5 } } ``` @@ -384,6 +389,22 @@ Search creatives across related campaigns by buyer reference: } ``` +### Example 11: Query Archived Creatives + +View archived creatives (excluded from default queries): + +```json +{ + "filters": { + "status": "archived" + }, + "sort": { + "field": "updated_date", + "direction": "desc" + } +} +``` + ## Query Optimization Tips ### 1. Use Specific Filters diff --git a/docs/reference/data-models.mdx b/docs/reference/data-models.mdx index 7f88e4e86a..0e66f3fc07 100644 --- a/docs/reference/data-models.mdx +++ b/docs/reference/data-models.mdx @@ -79,7 +79,7 @@ interface CreativeAsset { name: string; format: string; url?: string; - status: 'processing' | 'approved' | 'rejected' | 'pending_review'; + status: 'processing' | 'approved' | 'rejected' | 'pending_review' | 'archived'; compliance?: { status: string; issues?: string[]; @@ -166,7 +166,7 @@ type DeliveryType = 'guaranteed' | 'non_guaranteed'; type MediaBuyStatus = 'pending_activation' | 'active' | 'paused' | 'completed'; // Creative Status - Schema: /schemas/v2/enums/creative-status.json -type CreativeStatus = 'processing' | 'approved' | 'rejected' | 'pending_review'; +type CreativeStatus = 'processing' | 'approved' | 'rejected' | 'pending_review' | 'archived'; // Pacing - Schema: /schemas/v2/enums/pacing.json type Pacing = 'even' | 'asap' | 'front_loaded'; diff --git a/static/schemas/source/core/creative-asset.json b/static/schemas/source/core/creative-asset.json index c60f53a123..fbd302f1cb 100644 --- a/static/schemas/source/core/creative-asset.json +++ b/static/schemas/source/core/creative-asset.json @@ -96,9 +96,9 @@ "type": "string" } }, - "approved": { - "type": "boolean", - "description": "For generative creatives: set to true to approve and finalize, false to request regeneration with updated assets/message. Omit for non-generative creatives." + "status": { + "$ref": "/schemas/enums/creative-status.json", + "description": "For generative creatives: set to 'approved' to finalize, 'rejected' to request regeneration with updated assets/message. Omit for non-generative creatives (system will set based on processing state)." }, "weight": { "type": "number", diff --git a/static/schemas/source/core/creative-filters.json b/static/schemas/source/core/creative-filters.json index 75f5c5c962..3c5177a859 100644 --- a/static/schemas/source/core/creative-filters.json +++ b/static/schemas/source/core/creative-filters.json @@ -2,7 +2,7 @@ "$schema": "http://json-schema.org/draft-07/schema#", "$id": "/schemas/core/creative-filters.json", "title": "Creative Filters", - "description": "Filter criteria for querying creative assets from the centralized library", + "description": "Filter criteria for querying creative assets from the centralized library. By default, archived creatives are excluded from results. To include archived creatives, explicitly filter by status='archived' or include 'archived' in the statuses array.", "type": "object", "properties": { "formats": { diff --git a/static/schemas/source/enums/creative-status.json b/static/schemas/source/enums/creative-status.json index 9c9cf0f903..ed0b231368 100644 --- a/static/schemas/source/enums/creative-status.json +++ b/static/schemas/source/enums/creative-status.json @@ -8,12 +8,14 @@ "processing", "approved", "rejected", - "pending_review" + "pending_review", + "archived" ], "enumDescriptions": { "processing": "Creative is being processed or transcoded", "approved": "Creative has been approved and is ready for delivery", "rejected": "Creative has been rejected due to policy or technical issues", - "pending_review": "Creative is under review" + "pending_review": "Creative is under review", + "archived": "Creative has been archived and is excluded from default queries" } } diff --git a/static/schemas/source/media-buy/list-creatives-response.json b/static/schemas/source/media-buy/list-creatives-response.json index a5fde42279..1b05b2d3ff 100644 --- a/static/schemas/source/media-buy/list-creatives-response.json +++ b/static/schemas/source/media-buy/list-creatives-response.json @@ -182,29 +182,19 @@ "type": "string", "description": "Package identifier" }, - "package_name": { + "buyer_ref": { "type": "string", - "description": "Human-readable package name" + "description": "Buyer's reference identifier for this package" }, "assigned_date": { "type": "string", "format": "date-time", "description": "When this assignment was created" - }, - "status": { - "type": "string", - "enum": [ - "active", - "paused", - "ended" - ], - "description": "Status of this specific assignment" } }, "required": [ "package_id", - "assigned_date", - "status" + "assigned_date" ], "additionalProperties": true } @@ -293,6 +283,11 @@ "type": "object", "description": "Breakdown of creatives by status", "properties": { + "processing": { + "type": "integer", + "description": "Number of creatives being processed", + "minimum": 0 + }, "approved": { "type": "integer", "description": "Number of approved creatives", @@ -416,9 +411,8 @@ "assigned_packages": [ { "package_id": "pkg_ctv_001", - "package_name": "CTV Prime Time", - "assigned_date": "2024-01-16T09:00:00Z", - "status": "active" + "buyer_ref": "ctv_prime_time_q1", + "assigned_date": "2024-01-16T09:00:00Z" } ] }, diff --git a/v2.6-rc/docs/media-buy/task-reference/list_creatives.mdx b/v2.6-rc/docs/media-buy/task-reference/list_creatives.mdx index 6ba0951f9a..46e76a9d7d 100644 --- a/v2.6-rc/docs/media-buy/task-reference/list_creatives.mdx +++ b/v2.6-rc/docs/media-buy/task-reference/list_creatives.mdx @@ -52,6 +52,10 @@ The `list_creatives` task provides comprehensive search and filtering capabiliti } ``` + +**Archived creatives are excluded by default.** To include archived creatives in results, explicitly filter by `status: "archived"` or include `"archived"` in the `statuses` array. + + ### Tag-Based Filtering ```json @@ -189,7 +193,8 @@ The response provides comprehensive creative data with optional enrichment: "status_summary": { "approved": 20, "pending_review": 3, - "rejected": 2 + "rejected": 2, + "archived": 5 } } ``` @@ -384,6 +389,22 @@ Search creatives across related campaigns by buyer reference: } ``` +### Example 11: Query Archived Creatives + +View archived creatives (excluded from default queries): + +```json +{ + "filters": { + "status": "archived" + }, + "sort": { + "field": "updated_date", + "direction": "desc" + } +} +``` + ## Query Optimization Tips ### 1. Use Specific Filters diff --git a/v2.6-rc/docs/reference/data-models.mdx b/v2.6-rc/docs/reference/data-models.mdx index 7f88e4e86a..0e66f3fc07 100644 --- a/v2.6-rc/docs/reference/data-models.mdx +++ b/v2.6-rc/docs/reference/data-models.mdx @@ -79,7 +79,7 @@ interface CreativeAsset { name: string; format: string; url?: string; - status: 'processing' | 'approved' | 'rejected' | 'pending_review'; + status: 'processing' | 'approved' | 'rejected' | 'pending_review' | 'archived'; compliance?: { status: string; issues?: string[]; @@ -166,7 +166,7 @@ type DeliveryType = 'guaranteed' | 'non_guaranteed'; type MediaBuyStatus = 'pending_activation' | 'active' | 'paused' | 'completed'; // Creative Status - Schema: /schemas/v2/enums/creative-status.json -type CreativeStatus = 'processing' | 'approved' | 'rejected' | 'pending_review'; +type CreativeStatus = 'processing' | 'approved' | 'rejected' | 'pending_review' | 'archived'; // Pacing - Schema: /schemas/v2/enums/pacing.json type Pacing = 'even' | 'asap' | 'front_loaded'; From 57e56de49b9b9ff2cbe6049dfab4061a5838eb8a Mon Sep 17 00:00:00 2001 From: Brian O'Kelley Date: Fri, 23 Jan 2026 15:08:39 -0500 Subject: [PATCH 27/34] Add Media Channel Taxonomy (#811) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: Add Media Channel Taxonomy specification Introduces a standardized taxonomy distinguishing channels (where ads reach audiences), property types (addressable inventory), formats (how ads render), and buying models (how inventory is purchased). - Defines 19 media channels: web, ctv, mobile_app, social, search, linear_tv, radio, streaming_audio, podcast, dooh, ooh, print, cinema, email, gaming, influencer, conversational, sponsorship, commerce_media - Updates channels.json and property-type.json enums with new values and descriptions - Adds comprehensive specification document with channel definitions and use cases - Includes migration guidance mapping legacy channel values to new taxonomy - Updates documentation examples to use new channel taxonomy Co-Authored-By: Claude Haiku 4.5 * refactor: Rename conversational channel to ai_agents Co-Authored-By: Claude Opus 4.5 * docs: Clarify channel vs property type distinction and add edge cases - Add "Understanding Channels vs Property Types" section explaining buying context - Add desktop_app property type for Electron/Chromium wrapper applications - Refine ai_agents description to clarify it describes buying context, not technology - Add comprehensive edge cases section covering: - In-app browsers (WebViews) - Desktop apps as Chromium wrappers (Spotify, Discord) - AI widgets on publisher websites - Commerce vs web display ambiguity - Search vs AI agents distinction - Gaming vs mobile app classification - Influencer vs social differentiation Co-Authored-By: Claude Opus 4.5 * fix: Correct edge cases for WebViews and AI widgets - WebViews: Ads on destination sites (cnn.com via Facebook browser) are still web channel, not social - bought through standard web programmatic - AI widgets: Add user intent/focus dimension, similar to OLV distinction (peripheral vs primary focus) Co-Authored-By: Claude Opus 4.5 * chore: Update changeset to major (breaking change) Replacing channel enum values is a breaking change for existing implementations. Co-Authored-By: Claude Opus 4.5 * Add affiliate channel to Media Channel Taxonomy Adds affiliate as a distinct channel for performance-based publisher partnerships including affiliate networks, comparison sites, lead gen, coupon/deal sites, and cashback programs. Co-Authored-By: Claude Opus 4.5 * refactor: Switch to planning-oriented channel taxonomy (19 channels) Based on media planning expert feedback, channels now represent how buyers allocate budget rather than technical substrates. Key changes: - Remove web, mobile_app, ai_agents (substrates, not planning buckets) - Add display, olv (OLV = Online Video, distinct from CTV) - Rename commerce_media → retail_media, sponsorship → product_placement - Update examples in get_products, list_authorized_properties, and quick reference docs to use new channel values New 19-channel list: display, olv, social, search, ctv, linear_tv, radio, streaming_audio, podcast, dooh, ooh, print, cinema, email, gaming, retail_media, influencer, affiliate, product_placement Future considerations documented: messaging, xr, ai_agents Co-Authored-By: Claude Opus 4.5 --------- Co-authored-by: Claude Haiku 4.5 --- .changeset/media-channel-taxonomy.md | 13 + docs.json | 1 + .../media-buy/task-reference/get_products.mdx | 6 +- .../list_authorized_properties.mdx | 6 +- docs/reference/media-buy-quick-reference.mdx | 2 +- docs/reference/media-channel-taxonomy.mdx | 740 ++++++++++++++++++ docs/reference/release-notes.mdx | 2 +- static/schemas/source/enums/channels.json | 49 +- .../schemas/source/enums/property-type.json | 15 +- .../docs/reference/media-channel-taxonomy.mdx | 740 ++++++++++++++++++ 10 files changed, 1555 insertions(+), 19 deletions(-) create mode 100644 .changeset/media-channel-taxonomy.md create mode 100644 docs/reference/media-channel-taxonomy.mdx create mode 100644 v2.6-rc/docs/reference/media-channel-taxonomy.mdx diff --git a/.changeset/media-channel-taxonomy.md b/.changeset/media-channel-taxonomy.md new file mode 100644 index 0000000000..44576e35ac --- /dev/null +++ b/.changeset/media-channel-taxonomy.md @@ -0,0 +1,13 @@ +--- +"adcontextprotocol": major +--- + +Add Media Channel Taxonomy specification with standardized channel definitions. + +**BREAKING**: Replaces channel enum values (display, video, audio, native, retail → display, olv, social, search, ctv, etc.) + +- Introduces 19 planning-oriented media channels representing how buyers allocate budget +- Channels: display, olv, social, search, ctv, linear_tv, radio, streaming_audio, podcast, dooh, ooh, print, cinema, email, gaming, retail_media, influencer, affiliate, product_placement +- Adds desktop_app property type for Electron/Chromium wrapper applications +- Clear distinction between channels (planning abstractions), property types (addressable surfaces), and formats (how ads render) +- Includes migration guide and edge cases documentation diff --git a/docs.json b/docs.json index ab5bb3101e..1948f95e56 100644 --- a/docs.json +++ b/docs.json @@ -424,6 +424,7 @@ { "group": "Reference", "pages": [ + "v2.6-rc/docs/reference/media-channel-taxonomy", "v2.6-rc/docs/reference/roadmap", "v2.6-rc/docs/reference/release-notes", "v2.6-rc/docs/reference/changelog", diff --git a/docs/media-buy/task-reference/get_products.mdx b/docs/media-buy/task-reference/get_products.mdx index 5b1835d45e..799b0fed8c 100644 --- a/docs/media-buy/task-reference/get_products.mdx +++ b/docs/media-buy/task-reference/get_products.mdx @@ -145,7 +145,7 @@ asyncio.run(discover_with_filters()) | `end_date` | string | Campaign end date in ISO 8601 format (YYYY-MM-DD) for availability checks | | `budget_range` | object | Budget range to filter appropriate products (see Budget Range Object below) | | `countries` | string[] | Filter by target countries using ISO 3166-1 alpha-2 codes (case-insensitive, e.g., `["US", "CA", "GB"]`) | -| `channels` | string[] | Filter by advertising channels (e.g., `["display", "video", "dooh", "ctv", "audio", "native"]`) | +| `channels` | string[] | Filter by advertising channels (e.g., `["display", "ctv", "social", "streaming_audio"]`). See [Media Channel Taxonomy](/docs/reference/media-channel-taxonomy) | ### Budget Range Object @@ -298,7 +298,7 @@ const result = await testAgent.getProducts({ currency: 'USD' }, countries: ['US', 'CA'], - channels: ['display', 'video', 'ctv'], + channels: ['display', 'ctv', 'streaming_audio'], delivery_type: 'guaranteed' } }); @@ -329,7 +329,7 @@ async def discover_with_budget_and_dates(): 'currency': 'USD' }, 'countries': ['US', 'CA'], - 'channels': ['display', 'video', 'ctv'], + 'channels': ['web', 'ctv', 'streaming_audio'], 'delivery_type': 'guaranteed' } ) diff --git a/docs/media-buy/task-reference/list_authorized_properties.mdx b/docs/media-buy/task-reference/list_authorized_properties.mdx index 7f6b98d0b7..ab8d2dad94 100644 --- a/docs/media-buy/task-reference/list_authorized_properties.mdx +++ b/docs/media-buy/task-reference/list_authorized_properties.mdx @@ -28,7 +28,7 @@ Discover which publishers a sales agent is authorized to represent. Returns publ | Field | Description | |-------|-------------| | `publisher_domains` | Array of publisher domains this agent represents | -| `primary_channels` | Optional main advertising channels (ctv, display, video, audio, dooh, etc.) | +| `primary_channels` | Optional main advertising channels (e.g., `display`, `ctv`, `social`, `streaming_audio`). See [Media Channel Taxonomy](/docs/reference/media-channel-taxonomy) | | `primary_countries` | Optional main countries (ISO 3166-1 alpha-2 codes, case-insensitive) | | `portfolio_description` | Optional markdown description of portfolio and capabilities | | `last_updated` | Optional ISO 8601 timestamp of last publisher list update | @@ -404,7 +404,7 @@ Optional fields provide high-level portfolio information for quick filtering: ### primary_channels Main advertising channels in portfolio: -- Values: `display`, `video`, `dooh`, `ctv`, `podcast`, `retail`, etc. +- Values: `display`, `olv`, `dooh`, `ctv`, `podcast`, `retail_media`, etc. - See [Channels enum](https://adcontextprotocol.org/schemas/v2/enums/channels.json) - Use case: Filter "Do you have DOOH?" before examining properties @@ -435,7 +435,7 @@ Markdown description: **News Publisher**: ```json { - "primary_channels": ["display", "video", "native"], + "primary_channels": ["display", "olv"], "primary_countries": ["US", "GB", "AU"], "portfolio_description": "News and business publisher network. Desktop and mobile web with professional audience." } diff --git a/docs/reference/media-buy-quick-reference.mdx b/docs/reference/media-buy-quick-reference.mdx index 595bd8efca..65d2a3b4fc 100644 --- a/docs/reference/media-buy-quick-reference.mdx +++ b/docs/reference/media-buy-quick-reference.mdx @@ -42,7 +42,7 @@ Discover advertising products using natural language briefs. "url": "https://example.com" }, "filters": { - "channels": ["video", "ctv"], + "channels": ["display", "ctv"], "budget_range": { "min": 5000, "max": 50000 } } } diff --git a/docs/reference/media-channel-taxonomy.mdx b/docs/reference/media-channel-taxonomy.mdx new file mode 100644 index 0000000000..dbff98a547 --- /dev/null +++ b/docs/reference/media-channel-taxonomy.mdx @@ -0,0 +1,740 @@ +--- +title: Media Channel Taxonomy +sidebar_position: 15 +description: A standardized taxonomy for advertising media channels, designed for interoperability across media planning tools, ad tech platforms, and AI agents. +--- + +# Media Channel Taxonomy + + +**Status**: Draft Specification +**Version**: 1.0.0-draft +**Last Updated**: 2026-01-23 + + +This specification defines a standardized taxonomy for advertising media channels. It is designed for interoperability across media planning tools, ad tech platforms, and AI-powered advertising agents. + +## Motivation + +The advertising industry lacks a standardized channel taxonomy. While IAB Tech Lab provides taxonomies for content, audience, and ad products, no equivalent exists for media channels. This leads to: + +- Inconsistent channel naming across platforms +- Difficulty aggregating cross-channel campaign data +- Confusion between channels, formats, and buying models +- Friction in automated media planning workflows + +This specification addresses these gaps by defining: + +1. **Media Channels** - How buyers allocate budget (planning abstractions) +2. **Property Types** - Addressable inventory surfaces with verifiable ownership +3. **Clear distinction** between channels, property types, and formats + +## Design Philosophy + +**Channels represent how buyers plan and allocate budget**, not where ads technically render. + +This is a deliberate design choice. Buyers don't say "I have $500K for web" — they say "I have $500K for display" or "I have $300K for OLV." The channel taxonomy reflects this reality. + +### Key Principles + +1. **Planning-oriented**: Channels match how agencies structure media plans +2. **Lightweight tags**: Channels help buyers express intent, not enforce precise classification +3. **Multi-channel support**: Properties may align with multiple channels (YouTube = `olv`, `social`, `ctv`) +4. **Publisher-declared**: Publishers indicate which channels their inventory supports +5. **Agent-reconciled**: Sales agents match buyer intent with publisher claims + +### Channels vs Technical Substrates + +Channels deliberately avoid substrate-level concepts like "web" or "mobile app" because: +- Buyers don't plan that way +- Most digital inventory would fall into both categories +- The same placement can be bought different ways + +Instead, channels describe **buying contexts**: display, OLV, social, search, CTV, etc. + +## Terminology + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119). + +## Definitions + +### Media Channel + +A **media channel** describes how buyers allocate budget. It represents a planning abstraction that encodes assumptions about audience, environment, and buying approach. + +Channels are defined by **buying context**, not by: +- Technical substrate (web vs app) +- How the ad looks (that's a **format**) +- The specific technology serving the ad + +### Property Type + +A **property type** describes a specific addressable inventory surface where: +- Ownership can be verified (e.g., via `adagents.json`) +- Ads can be programmatically served +- Identifiers exist for the property (domains, app IDs, device IDs) + +Property types are technical classifications, distinct from channels. The same property may support multiple channels. + +### Format Category + +A **format category** describes HOW an ad renders - its creative unit type. Examples: `video`, `audio`, `display`, `native`. Formats are orthogonal to channels. + +## Understanding Channels vs Property Types + +| Concept | Question It Answers | Determined By | Example | +|---------|---------------------|---------------|---------| +| **Channel** | How do buyers allocate budget? | Planning context | `retail_media` | +| **Property Type** | Where does the ad technically render? | Addressable inventory surface | `website` | + +### Why This Matters + +Consider retail media: when a buyer allocates budget to "retail media," they're buying: +1. Sponsored products on retailer websites +2. Display ads on retailer apps +3. Off-site ads using retailer data +4. In-store digital screens + +All of these are `retail_media` channel, but the property types vary (`website`, `mobile_app`, `dooh`). + +### Multi-Channel Properties + +Properties can align with multiple channels. Examples: + +| Property | Channels | Reasoning | +|----------|----------|-----------| +| YouTube | `olv`, `social`, `ctv` | Different buying contexts on same platform | +| ESPN App | `olv`, `display` | Supports video and display inventory | +| Amazon | `retail_media`, `search`, `display` | Multiple ad products | + +### When to Use Each + +**Use channel when:** +- Filtering products by budget allocation category +- Reporting on media mix +- Expressing buyer intent in product discovery + +**Use property_type when:** +- Validating inventory ownership via `adagents.json` +- Technical ad serving decisions +- Platform-specific targeting + +## Media Channels + +### Channel Enum + +The following 19 channels MUST be supported. Implementations MAY extend with additional channels using the `ext` field. + +| Channel | Description | +|---------|-------------| +| `display` | Digital display advertising (banners, native, rich media) | +| `olv` | Online video outside CTV (pre-roll, outstream, in-app video) | +| `social` | Social media platforms | +| `search` | Search engine advertising | +| `ctv` | Connected TV and streaming on television screens | +| `linear_tv` | Traditional broadcast and cable television | +| `radio` | Traditional AM/FM radio broadcast | +| `streaming_audio` | Digital audio streaming services | +| `podcast` | Podcast advertising | +| `dooh` | Digital out-of-home screens | +| `ooh` | Classic out-of-home (billboards, transit) | +| `print` | Newspapers, magazines, print publications | +| `cinema` | Movie theater advertising | +| `email` | Email advertising and newsletters | +| `gaming` | In-game advertising | +| `retail_media` | Retail media networks and commerce marketplaces | +| `influencer` | Creator and influencer partnerships | +| `affiliate` | Affiliate networks and performance-based partnerships | +| `product_placement` | Product placement and branded content | + +### Channel Definitions + +#### `display` + +Digital display advertising including banners, native units, and rich media across web and app environments. + +**Includes**: +- Display banners on websites +- Display ads in mobile apps +- Native content units +- Rich media ads +- Interstitials (non-video) + +**Excludes**: +- Video ads (use `olv` or `ctv`) +- Social platform ads (use `social`) +- Search results (use `search`) +- Retail media placements (use `retail_media`) + +**Typical Formats**: display, native, rich_media + +#### `olv` + +Online video advertising delivered outside of CTV/television environments. + +**Includes**: +- Pre-roll, mid-roll, post-roll on websites +- In-app video ads +- Outstream/in-feed video +- YouTube video ads (when not on TV screens) +- Video on news sites, sports sites, etc. + +**Excludes**: +- CTV/streaming on TV screens (use `ctv`) +- Social platform video (use `social`) +- Linear TV (use `linear_tv`) +- Retail media video (use `retail_media`) + +**Typical Formats**: video + +**Note**: OLV (Online Video) is a distinct planning bucket from CTV. Agencies commonly budget separately for "OLV" and "CTV" campaigns. + +#### `social` + +Social media platform advertising, regardless of technical delivery surface. + +**Includes**: +- Meta platforms (Facebook, Instagram, Threads) +- X (Twitter) +- TikTok +- LinkedIn +- Snapchat +- Pinterest +- Reddit +- YouTube (when bought through social-style targeting) + +**Excludes**: +- Influencer content on social platforms (use `influencer`) +- Video ads bought for reach, not social engagement (consider `olv`) + +**Typical Formats**: display, video, native + +**Note**: Social is defined by BUYING CONTEXT (social platform ad tools) and audience engagement model. + +#### `search` + +Search engine results pages and search advertising networks. + +**Includes**: +- Google Search ads +- Microsoft Bing ads +- DuckDuckGo ads +- App store search ads +- Shopping/product listing ads in search context + +**Excludes**: +- Display ads on search engine properties (use `display`) +- Retail media search (use `retail_media`) + +**Typical Formats**: text, display (shopping) + +#### `ctv` + +Connected TV advertising delivered through streaming applications on television screens. + +**Includes**: +- Streaming service apps (Netflix, Hulu, Max, etc.) +- Virtual MVPDs (YouTube TV, Sling, etc.) +- Free ad-supported streaming TV (FAST) +- Smart TV native apps +- Gaming console streaming apps + +**Excludes**: +- Linear broadcast/cable (use `linear_tv`) +- Video on phones/tablets/desktops (use `olv`) +- YouTube on mobile (use `olv` or `social`) + +**Typical Formats**: video + +#### `linear_tv` + +Traditional broadcast and cable television advertising. + +**Includes**: +- National broadcast networks (ABC, CBS, NBC, Fox) +- Cable networks (ESPN, CNN, HGTV) +- Local broadcast stations +- Addressable linear TV + +**Excludes**: +- Streaming on TV screens (use `ctv`) +- TV Everywhere apps on mobile (use `olv`) + +**Typical Formats**: video + +#### `radio` + +Traditional AM/FM radio broadcast advertising. + +**Includes**: +- Terrestrial radio stations +- Satellite radio (SiriusXM terrestrial simulcast) +- HD Radio + +**Excludes**: +- Streaming audio services (use `streaming_audio`) +- Podcasts (use `podcast`) + +**Typical Formats**: audio + +#### `streaming_audio` + +Digital audio streaming services. + +**Includes**: +- Music streaming (Spotify, Apple Music, Amazon Music, Pandora) +- Audio content platforms +- Digital radio streams (iHeartRadio digital, TuneIn) + +**Excludes**: +- Podcasts (use `podcast`) +- Terrestrial radio simulcast (use `radio`) + +**Typical Formats**: audio, display (companion) + +#### `podcast` + +Podcast advertising, including host-read and dynamically inserted ads. + +**Includes**: +- Host-read sponsorships +- Dynamically inserted audio ads +- Podcast network advertising + +**Excludes**: +- Music streaming (use `streaming_audio`) +- Video podcasts on YouTube (use `olv` or `social`) + +**Typical Formats**: audio + +#### `dooh` + +Digital out-of-home advertising on electronic screens in public spaces. + +**Includes**: +- Digital billboards +- Transit screens (subway, bus shelters, airports) +- Retail/mall digital displays +- Gas station screens +- Elevator screens +- Stadium/venue digital signage + +**Excludes**: +- Static billboards (use `ooh`) +- Cinema screens (use `cinema`) + +**Typical Formats**: display, video + +#### `ooh` + +Classic out-of-home advertising on physical (non-digital) surfaces. + +**Includes**: +- Static billboards +- Transit posters +- Street furniture +- Wallscapes +- Wild postings + +**Excludes**: +- Digital screens (use `dooh`) + +**Typical Formats**: display (static) + +#### `print` + +Newspaper, magazine, and other print publication advertising. + +**Includes**: +- Newspaper display ads +- Magazine display ads +- Newspaper/magazine inserts +- Trade publication advertising + +**Excludes**: +- Digital versions of publications (use `display`) +- Direct mail + +**Typical Formats**: display (static) + +#### `cinema` + +Movie theater advertising. + +**Includes**: +- Pre-show advertising +- On-screen trailers and ads +- Lobby displays +- Concession advertising + +**Excludes**: +- Streaming movie services (use `ctv`) + +**Typical Formats**: video, display + +#### `email` + +Email advertising and sponsored newsletter content. + +**Includes**: +- Sponsored email newsletters +- Email display advertising +- Dedicated email sends + +**Excludes**: +- Transactional email +- CRM/owned email marketing + +**Typical Formats**: display, native + +#### `gaming` + +In-game advertising across gaming platforms. + +**Includes**: +- In-game display ads +- Rewarded video ads +- Playable ads +- Advergames +- Esports sponsorships +- Gaming influencer integrations + +**Excludes**: +- Ads in non-gaming apps (use `display` or `olv`) +- Gaming content on streaming platforms (use `ctv` or `olv`) + +**Typical Formats**: display, video, native + +#### `retail_media` + +Retail media networks and commerce marketplace advertising. + +**Includes**: +- Retail media networks (Amazon Ads, Walmart Connect, Target Roundel) +- Grocery and delivery platforms (Instacart, DoorDash, Uber) +- Travel marketplaces (Expedia, Booking.com, Kayak) +- Financial services marketplaces +- Sponsored product listings +- On-site display and video on commerce platforms +- Off-site ads using retailer first-party data + +**Excludes**: +- General display ads (use `display`) +- Social commerce (use `social`) +- Search ads on non-commerce platforms (use `search`) + +**Typical Formats**: native, display, video + +**Note**: Retail media is distinguished by its transactional context and closed-loop attribution capabilities. + +#### `influencer` + +Creator and influencer marketing partnerships. + +**Includes**: +- Sponsored content creation +- Brand ambassador programs +- Affiliate creator partnerships +- User-generated content campaigns + +**Excludes**: +- Ads placed on creator content by platforms (use `social`) +- Podcast host reads (use `podcast`) + +**Typical Formats**: video, native, display + +**Note**: `influencer` describes the BUYING MODEL (creator partnership) rather than where content appears. + +#### `affiliate` + +Affiliate networks, comparison sites, and performance-based publisher partnerships. + +**Includes**: +- Affiliate networks (CJ, Rakuten, Impact, Awin, ShareASale) +- Comparison shopping engines (NerdWallet, Bankrate, The Points Guy) +- Review and recommendation sites +- Coupon and deal sites (RetailMeNot, Honey) +- Content commerce (editorial with affiliate links) +- Lead generation sites +- Cashback and loyalty programs + +**Excludes**: +- Standard display ads on affiliate sites (use `display`) +- Influencer partnerships (use `influencer`) +- Retail media sponsored products (use `retail_media`) + +**Typical Formats**: native, display, text + +**Note**: `affiliate` describes the BUYING MODEL (performance-based, CPA/CPC/rev-share) rather than where content appears. + +#### `product_placement` + +Product placement, branded content, and sponsorship integrations. + +**Includes**: +- Traditional product placement (film, TV) +- Virtual product placement +- Branded entertainment +- Event sponsorships +- Naming rights +- Branded content series + +**Excludes**: +- Influencer partnerships (use `influencer`) +- Standard ad placements at sponsored events (use appropriate channel) + +**Typical Formats**: native, video + +## Property Types + +Property types describe addressable inventory surfaces with verifiable ownership. They are used in `adagents.json` for authorization validation. + +### Property Type Enum + +| Property Type | Description | Example Channels | +|---------------|-------------|------------------| +| `website` | Web properties accessible via browser | `display`, `olv` | +| `mobile_app` | Native mobile applications | `display`, `olv`, `social`, `gaming` | +| `ctv_app` | Connected TV applications | `ctv` | +| `desktop_app` | Desktop applications (Electron, native) | `streaming_audio`, `gaming` | +| `dooh` | Digital out-of-home screen networks | `dooh` | +| `podcast` | Podcast feeds and episodes | `podcast` | +| `radio` | Radio station properties | `radio` | +| `streaming_audio` | Digital audio streaming properties | `streaming_audio` | + +### Channels Without Property Types + +The following channels do not have corresponding property types because they lack addressable, verifiable inventory surfaces in the traditional sense: + +- `linear_tv` - Broadcast/cable inventory is managed through different authorization mechanisms +- `ooh` - Physical inventory lacks digital identifiers +- `print` - Physical publication inventory +- `cinema` - Theater inventory management systems +- `email` - Email list ownership differs from property authorization +- `influencer` - Creator relationships rather than property ownership +- `affiliate` - Performance-based partnerships, placements appear on partner websites +- `product_placement` - Content/event relationships rather than properties +- `retail_media` - Platform-managed inventory within retail ecosystems +- `search` - Platform-managed inventory +- `social` - Platform-managed inventory + +## Relationship Between Concepts + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ MEDIA CHANNEL │ +│ How buyers allocate budget (planning abstraction) │ +│ │ +│ display, olv, social, search, ctv, linear_tv, podcast, │ +│ streaming_audio, radio, dooh, ooh, print, cinema, email, │ +│ gaming, retail_media, influencer, affiliate, product_placement│ +└─────────────────────────────────────────────────────────────────┘ + +┌─────────────────────────────────────────────────────────────────┐ +│ PROPERTY TYPE │ +│ Addressable inventory with verifiable ownership (technical) │ +│ │ +│ website, mobile_app, ctv_app, desktop_app, dooh, │ +│ podcast, radio, streaming_audio │ +└─────────────────────────────────────────────────────────────────┘ + +┌─────────────────────────────────────────────────────────────────┐ +│ FORMAT CATEGORY │ +│ How the ad renders (orthogonal to channel) │ +│ │ +│ audio, video, display, native, rich_media, text │ +└─────────────────────────────────────────────────────────────────┘ +``` + +## Implementation + +### JSON Schema + +Channels are defined in the AdCP schema at: + +``` +/schemas/v1/enums/channels.json +``` + +```json +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/enums/channels.json", + "title": "Media Channel", + "description": "Standardized advertising media channels describing how buyers allocate budget", + "type": "string", + "enum": [ + "display", + "olv", + "social", + "search", + "ctv", + "linear_tv", + "radio", + "streaming_audio", + "podcast", + "dooh", + "ooh", + "print", + "cinema", + "email", + "gaming", + "retail_media", + "influencer", + "affiliate", + "product_placement" + ] +} +``` + +### Usage in Product Discovery + +When filtering products by channel: + +```json +{ + "filters": { + "channels": ["ctv", "olv", "streaming_audio"] + } +} +``` + +### Usage in Property Definitions + +Properties in `adagents.json` declare which channels they support: + +```json +{ + "properties": [ + { + "property_id": "youtube_app", + "property_type": "ctv_app", + "name": "YouTube CTV", + "supported_channels": ["ctv", "olv", "social"], + "identifiers": [ + {"type": "roku_store_id", "value": "12345"} + ] + } + ] +} +``` + +### Extensibility + +Implementations MAY support additional channels beyond this specification using the `ext` field pattern: + +```json +{ + "channel": "display", + "ext": { + "sub_channel": "native_content" + } +} +``` + +## Versioning + +This taxonomy follows [Semantic Versioning](https://semver.org/): + +- **MAJOR**: Removing channels, changing channel semantics +- **MINOR**: Adding new channels (append-only) +- **PATCH**: Clarifying descriptions, fixing typos + +Adding new channels is a MINOR version change and MUST NOT break existing implementations. + +## Migration from Legacy Channel Values + +Prior to this taxonomy, AdCP used a different set of channel values. The following table maps legacy values to the new taxonomy: + +| Legacy Value | New Channel(s) | Notes | +|--------------|----------------|-------| +| `display` | `display` | No change, but now excludes video | +| `video` | `olv`, `ctv` | Split by viewing environment | +| `audio` | `streaming_audio`, `podcast`, `radio` | Split by audio type | +| `native` | `display` | Native is a format, not a channel | +| `web` | `display`, `olv` | Web is a substrate, not a planning bucket | +| `mobile_app` | `display`, `olv`, `gaming` | App is a substrate, not a planning bucket | +| `dooh` | `dooh` | No change | +| `ctv` | `ctv` | No change | +| `podcast` | `podcast` | No change | +| `retail` | `retail_media` | Renamed | +| `commerce_media` | `retail_media` | Renamed | +| `social` | `social` | No change | +| `sponsorship` | `product_placement` | Renamed and refined | + +### Migration Guidance + +1. **Identify the planning context**: Determine HOW the buyer allocates budget, not where ads technically render. + +2. **Split video by environment**: If video was a single category, split into `olv` (desktop/mobile) and `ctv` (TV screens). + +3. **Remove substrate channels**: If you had `web` or `mobile_app` as channels, map to planning-oriented channels (`display`, `olv`) based on buying context. + +4. **Update filters**: When filtering products, use the new channel values. + +## Edge Cases and Ambiguities + +### YouTube Classification + +YouTube spans multiple channels depending on context: + +| Scenario | Channel | Reasoning | +|----------|---------|-----------| +| YouTube video ad on phone/desktop | `olv` or `social` | Depends on buying approach | +| YouTube video ad on CTV | `ctv` | TV screen environment | +| YouTube Shorts | `social` | Short-form social context | +| YouTube Music | `streaming_audio` | Audio streaming context | + +### Retail Media Complexity + +Retail media may eventually warrant sub-channels: + +| Scenario | Current | Potential Future | +|----------|---------|------------------| +| Sponsored products on Amazon | `retail_media` | `retail_media_search` | +| Display on retailer site | `retail_media` | `retail_media_display` | +| Off-site using retailer data | `retail_media` | `retail_media_offsite` | + +For now, use `retail_media` with format filters to distinguish. + +### Gaming vs Display/OLV + +| Scenario | Channel | Reasoning | +|----------|---------|-----------| +| Rewarded video in mobile game via Unity Ads | `gaming` | Gaming-specific ad network | +| Banner in casual game via AdMob general pool | `display` | Standard mobile programmatic | +| Esports tournament sponsorship | `gaming` | Gaming audience context | + +### Influencer vs Social + +| Scenario | Channel | Reasoning | +|----------|---------|-----------| +| Buying promoted posts through Instagram Ads | `social` | Platform ad tools | +| Contracting an influencer directly | `influencer` | Creator partnership | +| Platform-inserted ads around creator content | `social` | Platform ad tools | + +## Future Considerations + +The following channels may be added in future versions based on market evolution: + +- `messaging` - WhatsApp Business, Telegram ads +- `xr` - VR/AR advertising +- `ai_agents` - AI assistant and chatbot advertising + +## References + +- [IAB Tech Lab Taxonomies](https://github.com/InteractiveAdvertisingBureau/Taxonomies) - Content, Audience, Ad Product +- [OpenRTB/AdCOM](https://github.com/InteractiveAdvertisingBureau/AdCOM) - Placement types and media objects +- [Planmatic Media Plan Schema](https://github.com/planmatic/mediaplanschema) - Media planning data structures +- [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119) - Requirement level keywords + +## Changelog + +### 1.0.0-draft (2026-01-23) + +- Initial draft specification +- 19 channels defined (planning-oriented approach) +- 8 property types defined +- Clear distinction between channel (planning abstraction), property_type (technical surface), and format +- Multi-channel support for properties +- Migration guide from legacy values diff --git a/docs/reference/release-notes.mdx b/docs/reference/release-notes.mdx index a87e8ba344..e9e965e492 100644 --- a/docs/reference/release-notes.mdx +++ b/docs/reference/release-notes.mdx @@ -219,7 +219,7 @@ New structured filters in `get_products`: "currency": "USD" }, "countries": ["US", "CA"], - "channels": ["display", "video"] + "channels": ["display", "ctv"] } } ``` diff --git a/static/schemas/source/enums/channels.json b/static/schemas/source/enums/channels.json index a6bc0b24c7..e0005063a5 100644 --- a/static/schemas/source/enums/channels.json +++ b/static/schemas/source/enums/channels.json @@ -1,18 +1,49 @@ { "$schema": "http://json-schema.org/draft-07/schema#", "$id": "/schemas/enums/channels.json", - "title": "Advertising Channels", - "description": "Standard advertising channels supported by AdCP", + "title": "Media Channel", + "description": "Standardized advertising media channels describing how buyers allocate budget. Channels are planning abstractions, not technical substrates. See the Media Channel Taxonomy specification for detailed definitions.", "type": "string", "enum": [ "display", - "video", - "audio", - "native", - "dooh", + "olv", + "social", + "search", "ctv", + "linear_tv", + "radio", + "streaming_audio", "podcast", - "retail", - "social" - ] + "dooh", + "ooh", + "print", + "cinema", + "email", + "gaming", + "retail_media", + "influencer", + "affiliate", + "product_placement" + ], + "enumDescriptions": { + "display": "Digital display advertising (banners, native, rich media) across web and app", + "olv": "Online video advertising outside CTV (pre-roll, outstream, in-app video)", + "social": "Social media platforms (Facebook, Instagram, TikTok, LinkedIn, etc.)", + "search": "Search engine advertising and search networks", + "ctv": "Connected TV and streaming on television screens", + "linear_tv": "Traditional broadcast and cable television", + "radio": "Traditional AM/FM radio broadcast", + "streaming_audio": "Digital audio streaming services (Spotify, Pandora, etc.)", + "podcast": "Podcast advertising (host-read or dynamically inserted)", + "dooh": "Digital out-of-home screens in public spaces", + "ooh": "Classic out-of-home (physical billboards, transit, etc.)", + "print": "Newspapers, magazines, and other print publications", + "cinema": "Movie theater advertising", + "email": "Email advertising and sponsored newsletter content", + "gaming": "In-game advertising across platforms", + "retail_media": "Retail media networks and commerce marketplaces (Amazon, Walmart, Instacart)", + "influencer": "Creator and influencer marketing partnerships", + "affiliate": "Affiliate networks, comparison sites, and performance-based partnerships", + "product_placement": "Product placement, branded content, and sponsorship integrations" + } } diff --git a/static/schemas/source/enums/property-type.json b/static/schemas/source/enums/property-type.json index 0b0d104714..9bf4d054a2 100644 --- a/static/schemas/source/enums/property-type.json +++ b/static/schemas/source/enums/property-type.json @@ -2,15 +2,26 @@ "$schema": "http://json-schema.org/draft-07/schema#", "$id": "/schemas/enums/property-type.json", "title": "Property Type", - "description": "Types of advertising properties that can be represented in AdCP", + "description": "Types of addressable advertising properties with verifiable ownership. Property types are a subset of media channels - they represent inventory surfaces that can be validated via adagents.json.", "type": "string", "enum": [ "website", "mobile_app", "ctv_app", + "desktop_app", "dooh", "podcast", "radio", "streaming_audio" - ] + ], + "enumDescriptions": { + "website": "Web properties accessible via browser, identified by domain", + "mobile_app": "Native mobile applications, identified by app store IDs or bundle identifiers", + "ctv_app": "Connected TV applications, identified by platform-specific store IDs", + "desktop_app": "Desktop applications (Electron, native, Chromium wrappers), identified by application bundle IDs", + "dooh": "Digital out-of-home screen networks, identified by network/venue IDs", + "podcast": "Podcast feeds and episodes, identified by RSS feed URLs or podcast IDs", + "radio": "Radio station properties, identified by call signs or station IDs", + "streaming_audio": "Digital audio streaming properties, identified by platform-specific IDs" + } } diff --git a/v2.6-rc/docs/reference/media-channel-taxonomy.mdx b/v2.6-rc/docs/reference/media-channel-taxonomy.mdx new file mode 100644 index 0000000000..dbff98a547 --- /dev/null +++ b/v2.6-rc/docs/reference/media-channel-taxonomy.mdx @@ -0,0 +1,740 @@ +--- +title: Media Channel Taxonomy +sidebar_position: 15 +description: A standardized taxonomy for advertising media channels, designed for interoperability across media planning tools, ad tech platforms, and AI agents. +--- + +# Media Channel Taxonomy + + +**Status**: Draft Specification +**Version**: 1.0.0-draft +**Last Updated**: 2026-01-23 + + +This specification defines a standardized taxonomy for advertising media channels. It is designed for interoperability across media planning tools, ad tech platforms, and AI-powered advertising agents. + +## Motivation + +The advertising industry lacks a standardized channel taxonomy. While IAB Tech Lab provides taxonomies for content, audience, and ad products, no equivalent exists for media channels. This leads to: + +- Inconsistent channel naming across platforms +- Difficulty aggregating cross-channel campaign data +- Confusion between channels, formats, and buying models +- Friction in automated media planning workflows + +This specification addresses these gaps by defining: + +1. **Media Channels** - How buyers allocate budget (planning abstractions) +2. **Property Types** - Addressable inventory surfaces with verifiable ownership +3. **Clear distinction** between channels, property types, and formats + +## Design Philosophy + +**Channels represent how buyers plan and allocate budget**, not where ads technically render. + +This is a deliberate design choice. Buyers don't say "I have $500K for web" — they say "I have $500K for display" or "I have $300K for OLV." The channel taxonomy reflects this reality. + +### Key Principles + +1. **Planning-oriented**: Channels match how agencies structure media plans +2. **Lightweight tags**: Channels help buyers express intent, not enforce precise classification +3. **Multi-channel support**: Properties may align with multiple channels (YouTube = `olv`, `social`, `ctv`) +4. **Publisher-declared**: Publishers indicate which channels their inventory supports +5. **Agent-reconciled**: Sales agents match buyer intent with publisher claims + +### Channels vs Technical Substrates + +Channels deliberately avoid substrate-level concepts like "web" or "mobile app" because: +- Buyers don't plan that way +- Most digital inventory would fall into both categories +- The same placement can be bought different ways + +Instead, channels describe **buying contexts**: display, OLV, social, search, CTV, etc. + +## Terminology + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119). + +## Definitions + +### Media Channel + +A **media channel** describes how buyers allocate budget. It represents a planning abstraction that encodes assumptions about audience, environment, and buying approach. + +Channels are defined by **buying context**, not by: +- Technical substrate (web vs app) +- How the ad looks (that's a **format**) +- The specific technology serving the ad + +### Property Type + +A **property type** describes a specific addressable inventory surface where: +- Ownership can be verified (e.g., via `adagents.json`) +- Ads can be programmatically served +- Identifiers exist for the property (domains, app IDs, device IDs) + +Property types are technical classifications, distinct from channels. The same property may support multiple channels. + +### Format Category + +A **format category** describes HOW an ad renders - its creative unit type. Examples: `video`, `audio`, `display`, `native`. Formats are orthogonal to channels. + +## Understanding Channels vs Property Types + +| Concept | Question It Answers | Determined By | Example | +|---------|---------------------|---------------|---------| +| **Channel** | How do buyers allocate budget? | Planning context | `retail_media` | +| **Property Type** | Where does the ad technically render? | Addressable inventory surface | `website` | + +### Why This Matters + +Consider retail media: when a buyer allocates budget to "retail media," they're buying: +1. Sponsored products on retailer websites +2. Display ads on retailer apps +3. Off-site ads using retailer data +4. In-store digital screens + +All of these are `retail_media` channel, but the property types vary (`website`, `mobile_app`, `dooh`). + +### Multi-Channel Properties + +Properties can align with multiple channels. Examples: + +| Property | Channels | Reasoning | +|----------|----------|-----------| +| YouTube | `olv`, `social`, `ctv` | Different buying contexts on same platform | +| ESPN App | `olv`, `display` | Supports video and display inventory | +| Amazon | `retail_media`, `search`, `display` | Multiple ad products | + +### When to Use Each + +**Use channel when:** +- Filtering products by budget allocation category +- Reporting on media mix +- Expressing buyer intent in product discovery + +**Use property_type when:** +- Validating inventory ownership via `adagents.json` +- Technical ad serving decisions +- Platform-specific targeting + +## Media Channels + +### Channel Enum + +The following 19 channels MUST be supported. Implementations MAY extend with additional channels using the `ext` field. + +| Channel | Description | +|---------|-------------| +| `display` | Digital display advertising (banners, native, rich media) | +| `olv` | Online video outside CTV (pre-roll, outstream, in-app video) | +| `social` | Social media platforms | +| `search` | Search engine advertising | +| `ctv` | Connected TV and streaming on television screens | +| `linear_tv` | Traditional broadcast and cable television | +| `radio` | Traditional AM/FM radio broadcast | +| `streaming_audio` | Digital audio streaming services | +| `podcast` | Podcast advertising | +| `dooh` | Digital out-of-home screens | +| `ooh` | Classic out-of-home (billboards, transit) | +| `print` | Newspapers, magazines, print publications | +| `cinema` | Movie theater advertising | +| `email` | Email advertising and newsletters | +| `gaming` | In-game advertising | +| `retail_media` | Retail media networks and commerce marketplaces | +| `influencer` | Creator and influencer partnerships | +| `affiliate` | Affiliate networks and performance-based partnerships | +| `product_placement` | Product placement and branded content | + +### Channel Definitions + +#### `display` + +Digital display advertising including banners, native units, and rich media across web and app environments. + +**Includes**: +- Display banners on websites +- Display ads in mobile apps +- Native content units +- Rich media ads +- Interstitials (non-video) + +**Excludes**: +- Video ads (use `olv` or `ctv`) +- Social platform ads (use `social`) +- Search results (use `search`) +- Retail media placements (use `retail_media`) + +**Typical Formats**: display, native, rich_media + +#### `olv` + +Online video advertising delivered outside of CTV/television environments. + +**Includes**: +- Pre-roll, mid-roll, post-roll on websites +- In-app video ads +- Outstream/in-feed video +- YouTube video ads (when not on TV screens) +- Video on news sites, sports sites, etc. + +**Excludes**: +- CTV/streaming on TV screens (use `ctv`) +- Social platform video (use `social`) +- Linear TV (use `linear_tv`) +- Retail media video (use `retail_media`) + +**Typical Formats**: video + +**Note**: OLV (Online Video) is a distinct planning bucket from CTV. Agencies commonly budget separately for "OLV" and "CTV" campaigns. + +#### `social` + +Social media platform advertising, regardless of technical delivery surface. + +**Includes**: +- Meta platforms (Facebook, Instagram, Threads) +- X (Twitter) +- TikTok +- LinkedIn +- Snapchat +- Pinterest +- Reddit +- YouTube (when bought through social-style targeting) + +**Excludes**: +- Influencer content on social platforms (use `influencer`) +- Video ads bought for reach, not social engagement (consider `olv`) + +**Typical Formats**: display, video, native + +**Note**: Social is defined by BUYING CONTEXT (social platform ad tools) and audience engagement model. + +#### `search` + +Search engine results pages and search advertising networks. + +**Includes**: +- Google Search ads +- Microsoft Bing ads +- DuckDuckGo ads +- App store search ads +- Shopping/product listing ads in search context + +**Excludes**: +- Display ads on search engine properties (use `display`) +- Retail media search (use `retail_media`) + +**Typical Formats**: text, display (shopping) + +#### `ctv` + +Connected TV advertising delivered through streaming applications on television screens. + +**Includes**: +- Streaming service apps (Netflix, Hulu, Max, etc.) +- Virtual MVPDs (YouTube TV, Sling, etc.) +- Free ad-supported streaming TV (FAST) +- Smart TV native apps +- Gaming console streaming apps + +**Excludes**: +- Linear broadcast/cable (use `linear_tv`) +- Video on phones/tablets/desktops (use `olv`) +- YouTube on mobile (use `olv` or `social`) + +**Typical Formats**: video + +#### `linear_tv` + +Traditional broadcast and cable television advertising. + +**Includes**: +- National broadcast networks (ABC, CBS, NBC, Fox) +- Cable networks (ESPN, CNN, HGTV) +- Local broadcast stations +- Addressable linear TV + +**Excludes**: +- Streaming on TV screens (use `ctv`) +- TV Everywhere apps on mobile (use `olv`) + +**Typical Formats**: video + +#### `radio` + +Traditional AM/FM radio broadcast advertising. + +**Includes**: +- Terrestrial radio stations +- Satellite radio (SiriusXM terrestrial simulcast) +- HD Radio + +**Excludes**: +- Streaming audio services (use `streaming_audio`) +- Podcasts (use `podcast`) + +**Typical Formats**: audio + +#### `streaming_audio` + +Digital audio streaming services. + +**Includes**: +- Music streaming (Spotify, Apple Music, Amazon Music, Pandora) +- Audio content platforms +- Digital radio streams (iHeartRadio digital, TuneIn) + +**Excludes**: +- Podcasts (use `podcast`) +- Terrestrial radio simulcast (use `radio`) + +**Typical Formats**: audio, display (companion) + +#### `podcast` + +Podcast advertising, including host-read and dynamically inserted ads. + +**Includes**: +- Host-read sponsorships +- Dynamically inserted audio ads +- Podcast network advertising + +**Excludes**: +- Music streaming (use `streaming_audio`) +- Video podcasts on YouTube (use `olv` or `social`) + +**Typical Formats**: audio + +#### `dooh` + +Digital out-of-home advertising on electronic screens in public spaces. + +**Includes**: +- Digital billboards +- Transit screens (subway, bus shelters, airports) +- Retail/mall digital displays +- Gas station screens +- Elevator screens +- Stadium/venue digital signage + +**Excludes**: +- Static billboards (use `ooh`) +- Cinema screens (use `cinema`) + +**Typical Formats**: display, video + +#### `ooh` + +Classic out-of-home advertising on physical (non-digital) surfaces. + +**Includes**: +- Static billboards +- Transit posters +- Street furniture +- Wallscapes +- Wild postings + +**Excludes**: +- Digital screens (use `dooh`) + +**Typical Formats**: display (static) + +#### `print` + +Newspaper, magazine, and other print publication advertising. + +**Includes**: +- Newspaper display ads +- Magazine display ads +- Newspaper/magazine inserts +- Trade publication advertising + +**Excludes**: +- Digital versions of publications (use `display`) +- Direct mail + +**Typical Formats**: display (static) + +#### `cinema` + +Movie theater advertising. + +**Includes**: +- Pre-show advertising +- On-screen trailers and ads +- Lobby displays +- Concession advertising + +**Excludes**: +- Streaming movie services (use `ctv`) + +**Typical Formats**: video, display + +#### `email` + +Email advertising and sponsored newsletter content. + +**Includes**: +- Sponsored email newsletters +- Email display advertising +- Dedicated email sends + +**Excludes**: +- Transactional email +- CRM/owned email marketing + +**Typical Formats**: display, native + +#### `gaming` + +In-game advertising across gaming platforms. + +**Includes**: +- In-game display ads +- Rewarded video ads +- Playable ads +- Advergames +- Esports sponsorships +- Gaming influencer integrations + +**Excludes**: +- Ads in non-gaming apps (use `display` or `olv`) +- Gaming content on streaming platforms (use `ctv` or `olv`) + +**Typical Formats**: display, video, native + +#### `retail_media` + +Retail media networks and commerce marketplace advertising. + +**Includes**: +- Retail media networks (Amazon Ads, Walmart Connect, Target Roundel) +- Grocery and delivery platforms (Instacart, DoorDash, Uber) +- Travel marketplaces (Expedia, Booking.com, Kayak) +- Financial services marketplaces +- Sponsored product listings +- On-site display and video on commerce platforms +- Off-site ads using retailer first-party data + +**Excludes**: +- General display ads (use `display`) +- Social commerce (use `social`) +- Search ads on non-commerce platforms (use `search`) + +**Typical Formats**: native, display, video + +**Note**: Retail media is distinguished by its transactional context and closed-loop attribution capabilities. + +#### `influencer` + +Creator and influencer marketing partnerships. + +**Includes**: +- Sponsored content creation +- Brand ambassador programs +- Affiliate creator partnerships +- User-generated content campaigns + +**Excludes**: +- Ads placed on creator content by platforms (use `social`) +- Podcast host reads (use `podcast`) + +**Typical Formats**: video, native, display + +**Note**: `influencer` describes the BUYING MODEL (creator partnership) rather than where content appears. + +#### `affiliate` + +Affiliate networks, comparison sites, and performance-based publisher partnerships. + +**Includes**: +- Affiliate networks (CJ, Rakuten, Impact, Awin, ShareASale) +- Comparison shopping engines (NerdWallet, Bankrate, The Points Guy) +- Review and recommendation sites +- Coupon and deal sites (RetailMeNot, Honey) +- Content commerce (editorial with affiliate links) +- Lead generation sites +- Cashback and loyalty programs + +**Excludes**: +- Standard display ads on affiliate sites (use `display`) +- Influencer partnerships (use `influencer`) +- Retail media sponsored products (use `retail_media`) + +**Typical Formats**: native, display, text + +**Note**: `affiliate` describes the BUYING MODEL (performance-based, CPA/CPC/rev-share) rather than where content appears. + +#### `product_placement` + +Product placement, branded content, and sponsorship integrations. + +**Includes**: +- Traditional product placement (film, TV) +- Virtual product placement +- Branded entertainment +- Event sponsorships +- Naming rights +- Branded content series + +**Excludes**: +- Influencer partnerships (use `influencer`) +- Standard ad placements at sponsored events (use appropriate channel) + +**Typical Formats**: native, video + +## Property Types + +Property types describe addressable inventory surfaces with verifiable ownership. They are used in `adagents.json` for authorization validation. + +### Property Type Enum + +| Property Type | Description | Example Channels | +|---------------|-------------|------------------| +| `website` | Web properties accessible via browser | `display`, `olv` | +| `mobile_app` | Native mobile applications | `display`, `olv`, `social`, `gaming` | +| `ctv_app` | Connected TV applications | `ctv` | +| `desktop_app` | Desktop applications (Electron, native) | `streaming_audio`, `gaming` | +| `dooh` | Digital out-of-home screen networks | `dooh` | +| `podcast` | Podcast feeds and episodes | `podcast` | +| `radio` | Radio station properties | `radio` | +| `streaming_audio` | Digital audio streaming properties | `streaming_audio` | + +### Channels Without Property Types + +The following channels do not have corresponding property types because they lack addressable, verifiable inventory surfaces in the traditional sense: + +- `linear_tv` - Broadcast/cable inventory is managed through different authorization mechanisms +- `ooh` - Physical inventory lacks digital identifiers +- `print` - Physical publication inventory +- `cinema` - Theater inventory management systems +- `email` - Email list ownership differs from property authorization +- `influencer` - Creator relationships rather than property ownership +- `affiliate` - Performance-based partnerships, placements appear on partner websites +- `product_placement` - Content/event relationships rather than properties +- `retail_media` - Platform-managed inventory within retail ecosystems +- `search` - Platform-managed inventory +- `social` - Platform-managed inventory + +## Relationship Between Concepts + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ MEDIA CHANNEL │ +│ How buyers allocate budget (planning abstraction) │ +│ │ +│ display, olv, social, search, ctv, linear_tv, podcast, │ +│ streaming_audio, radio, dooh, ooh, print, cinema, email, │ +│ gaming, retail_media, influencer, affiliate, product_placement│ +└─────────────────────────────────────────────────────────────────┘ + +┌─────────────────────────────────────────────────────────────────┐ +│ PROPERTY TYPE │ +│ Addressable inventory with verifiable ownership (technical) │ +│ │ +│ website, mobile_app, ctv_app, desktop_app, dooh, │ +│ podcast, radio, streaming_audio │ +└─────────────────────────────────────────────────────────────────┘ + +┌─────────────────────────────────────────────────────────────────┐ +│ FORMAT CATEGORY │ +│ How the ad renders (orthogonal to channel) │ +│ │ +│ audio, video, display, native, rich_media, text │ +└─────────────────────────────────────────────────────────────────┘ +``` + +## Implementation + +### JSON Schema + +Channels are defined in the AdCP schema at: + +``` +/schemas/v1/enums/channels.json +``` + +```json +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/enums/channels.json", + "title": "Media Channel", + "description": "Standardized advertising media channels describing how buyers allocate budget", + "type": "string", + "enum": [ + "display", + "olv", + "social", + "search", + "ctv", + "linear_tv", + "radio", + "streaming_audio", + "podcast", + "dooh", + "ooh", + "print", + "cinema", + "email", + "gaming", + "retail_media", + "influencer", + "affiliate", + "product_placement" + ] +} +``` + +### Usage in Product Discovery + +When filtering products by channel: + +```json +{ + "filters": { + "channels": ["ctv", "olv", "streaming_audio"] + } +} +``` + +### Usage in Property Definitions + +Properties in `adagents.json` declare which channels they support: + +```json +{ + "properties": [ + { + "property_id": "youtube_app", + "property_type": "ctv_app", + "name": "YouTube CTV", + "supported_channels": ["ctv", "olv", "social"], + "identifiers": [ + {"type": "roku_store_id", "value": "12345"} + ] + } + ] +} +``` + +### Extensibility + +Implementations MAY support additional channels beyond this specification using the `ext` field pattern: + +```json +{ + "channel": "display", + "ext": { + "sub_channel": "native_content" + } +} +``` + +## Versioning + +This taxonomy follows [Semantic Versioning](https://semver.org/): + +- **MAJOR**: Removing channels, changing channel semantics +- **MINOR**: Adding new channels (append-only) +- **PATCH**: Clarifying descriptions, fixing typos + +Adding new channels is a MINOR version change and MUST NOT break existing implementations. + +## Migration from Legacy Channel Values + +Prior to this taxonomy, AdCP used a different set of channel values. The following table maps legacy values to the new taxonomy: + +| Legacy Value | New Channel(s) | Notes | +|--------------|----------------|-------| +| `display` | `display` | No change, but now excludes video | +| `video` | `olv`, `ctv` | Split by viewing environment | +| `audio` | `streaming_audio`, `podcast`, `radio` | Split by audio type | +| `native` | `display` | Native is a format, not a channel | +| `web` | `display`, `olv` | Web is a substrate, not a planning bucket | +| `mobile_app` | `display`, `olv`, `gaming` | App is a substrate, not a planning bucket | +| `dooh` | `dooh` | No change | +| `ctv` | `ctv` | No change | +| `podcast` | `podcast` | No change | +| `retail` | `retail_media` | Renamed | +| `commerce_media` | `retail_media` | Renamed | +| `social` | `social` | No change | +| `sponsorship` | `product_placement` | Renamed and refined | + +### Migration Guidance + +1. **Identify the planning context**: Determine HOW the buyer allocates budget, not where ads technically render. + +2. **Split video by environment**: If video was a single category, split into `olv` (desktop/mobile) and `ctv` (TV screens). + +3. **Remove substrate channels**: If you had `web` or `mobile_app` as channels, map to planning-oriented channels (`display`, `olv`) based on buying context. + +4. **Update filters**: When filtering products, use the new channel values. + +## Edge Cases and Ambiguities + +### YouTube Classification + +YouTube spans multiple channels depending on context: + +| Scenario | Channel | Reasoning | +|----------|---------|-----------| +| YouTube video ad on phone/desktop | `olv` or `social` | Depends on buying approach | +| YouTube video ad on CTV | `ctv` | TV screen environment | +| YouTube Shorts | `social` | Short-form social context | +| YouTube Music | `streaming_audio` | Audio streaming context | + +### Retail Media Complexity + +Retail media may eventually warrant sub-channels: + +| Scenario | Current | Potential Future | +|----------|---------|------------------| +| Sponsored products on Amazon | `retail_media` | `retail_media_search` | +| Display on retailer site | `retail_media` | `retail_media_display` | +| Off-site using retailer data | `retail_media` | `retail_media_offsite` | + +For now, use `retail_media` with format filters to distinguish. + +### Gaming vs Display/OLV + +| Scenario | Channel | Reasoning | +|----------|---------|-----------| +| Rewarded video in mobile game via Unity Ads | `gaming` | Gaming-specific ad network | +| Banner in casual game via AdMob general pool | `display` | Standard mobile programmatic | +| Esports tournament sponsorship | `gaming` | Gaming audience context | + +### Influencer vs Social + +| Scenario | Channel | Reasoning | +|----------|---------|-----------| +| Buying promoted posts through Instagram Ads | `social` | Platform ad tools | +| Contracting an influencer directly | `influencer` | Creator partnership | +| Platform-inserted ads around creator content | `social` | Platform ad tools | + +## Future Considerations + +The following channels may be added in future versions based on market evolution: + +- `messaging` - WhatsApp Business, Telegram ads +- `xr` - VR/AR advertising +- `ai_agents` - AI assistant and chatbot advertising + +## References + +- [IAB Tech Lab Taxonomies](https://github.com/InteractiveAdvertisingBureau/Taxonomies) - Content, Audience, Ad Product +- [OpenRTB/AdCOM](https://github.com/InteractiveAdvertisingBureau/AdCOM) - Placement types and media objects +- [Planmatic Media Plan Schema](https://github.com/planmatic/mediaplanschema) - Media planning data structures +- [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119) - Requirement level keywords + +## Changelog + +### 1.0.0-draft (2026-01-23) + +- Initial draft specification +- 19 channels defined (planning-oriented approach) +- 8 property types defined +- Clear distinction between channel (planning abstraction), property_type (technical surface), and format +- Multi-channel support for properties +- Migration guide from legacy values From ce8fa031c30bf84f46b19a045c5baf49100e9a57 Mon Sep 17 00:00:00 2001 From: Brian O'Kelley Date: Sat, 24 Jan 2026 06:42:03 -0500 Subject: [PATCH 28/34] docs: Add campaign lifecycle sequence diagram to property governance (#854) Add a mermaid sequence diagram and narrative explaining the end-to-end workflow for property governance across three phases: - Campaign Planning: orchestrator creates property lists, decisioning platform fetches and caches - Bid Time: decisioning platform uses local cache only (no governance calls) - Monitoring: webhooks notify of changes, decisioning platform re-fetches Notes that AXE segments are an optional implementation mechanism for caching. Co-authored-by: Claude Opus 4.5 --- docs/governance/property/index.mdx | 54 ++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/docs/governance/property/index.mdx b/docs/governance/property/index.mdx index 8bff63f4e6..674d1fc8f1 100644 --- a/docs/governance/property/index.mdx +++ b/docs/governance/property/index.mdx @@ -137,6 +137,60 @@ flowchart TB Buyer -->|get_property_list with auth_token| Seller ``` +## Campaign Lifecycle + +Property governance operates across three distinct timing contexts. The key principle: **all governance evaluation happens at setup time**, with bid-time decisions using only cached data. + +```mermaid +sequenceDiagram + participant O as Orchestrator + participant G as Governance Agent + participant D as Decisioning Platform + + rect rgb(240, 248, 255) + Note over O,D: Phase 1: Campaign Planning (minutes-hours) + O->>G: create_property_list(filters, brand_manifest) + G-->>O: list_id, auth_token + O->>D: Share list_id + auth_token + D->>G: get_property_list(list_id, auth_token, resolve=true) + G-->>D: identifiers[] (pass/fail list, no scores) + D->>G: Register webhook for list updates + D->>D: Cache locally (optionally as AXE segments) + end + + rect rgb(255, 248, 240) + Note over O,D: Phase 2: Bid Time (under 100ms, NO governance calls) + D->>D: Check domain against cached allowlist + Note right of D: May use AXE axei/axex segments
or direct domain lookup + D->>D: Pass → bid, Fail → skip + end + + rect rgb(248, 255, 240) + Note over O,D: Phase 3: Monitoring (during flight) + G-->>D: Webhook: list changed (counts only) + D->>G: get_property_list(list_id, auth_token, resolve=true) + G-->>D: Updated identifiers[] + D->>D: Update cached allowlist + end +``` + +### Phase 1: Campaign Planning + +During campaign setup, the orchestrator creates property lists on governance agents with filters and brand manifests. The governance agent evaluates properties and returns a **pass/fail list of identifiers** (no raw scores are exposed). The orchestrator shares the `list_id` and `auth_token` with the decisioning platform, which fetches and caches the resolved list. + +### Phase 2: Bid Time + +At bid time, the decisioning platform uses **only its local cache**—no calls to governance agents. Latency requirements (under 100ms) make real-time API calls impractical. The decisioning platform may implement this cache as: + +- **Direct domain lookup**: In-memory set of approved domains +- **AXE segments**: Cache domains as `axei` (include) or `axex` (exclude) segments for impression-level filtering + +The choice of caching mechanism is implementation-specific; the protocol only requires that bid-time decisions use cached data. + +### Phase 3: Monitoring + +During campaign flight, governance agents continue evaluating properties. When a property's compliance status changes, the agent sends a webhook notification to registered subscribers. The webhook contains **change counts only** (not scores or reasons)—the decisioning platform must call `get_property_list` to fetch the updated list and refresh its cache. + ## Sharing Property Lists with Sellers Once a buyer has a compliant property list, they share it with sellers: From 4fe8f57c96f5a1835848787611fad0225abbfdce Mon Sep 17 00:00:00 2001 From: Brian O'Kelley Date: Sat, 24 Jan 2026 09:04:30 -0500 Subject: [PATCH 29/34] docs: Document property_features for governance agent discovery (#855) Add documentation explaining how publishers declare governance agents in adagents.json via the property_features field, enabling buyers to discover which agents (Scope3, TAG, OneTrust, etc.) have compliance, sustainability, or quality data for properties. - Add property_features field documentation to adagents.mdx - Add governance agent discovery workflow with sequence diagram - Document vendor extension pattern via ext blocks - Update index.mdx to include discovery as 5th governance concern - Add discovery section to list_property_features task doc Co-authored-by: Claude Opus 4.5 --- .changeset/tricky-ideas-try.md | 4 + docs/governance/property/adagents.mdx | 133 ++++++++++++++++- docs/governance/property/index.mdx | 136 +++++++++--------- docs/governance/property/specification.mdx | 42 +++++- .../property/tasks/list_property_features.mdx | 60 +++++++- 5 files changed, 294 insertions(+), 81 deletions(-) create mode 100644 .changeset/tricky-ideas-try.md diff --git a/.changeset/tricky-ideas-try.md b/.changeset/tricky-ideas-try.md new file mode 100644 index 0000000000..eee124102b --- /dev/null +++ b/.changeset/tricky-ideas-try.md @@ -0,0 +1,4 @@ +--- +--- + +docs: Document property_features field for governance agent discovery in adagents.json diff --git a/docs/governance/property/adagents.mdx b/docs/governance/property/adagents.mdx index ed8b17535c..84919e95da 100644 --- a/docs/governance/property/adagents.mdx +++ b/docs/governance/property/adagents.mdx @@ -65,6 +65,7 @@ The file must be valid JSON with UTF-8 encoding and return HTTP 200 status. - **`domain`** *(optional)*: Primary domain of managing entity - **`seller_id`** *(optional)*: Seller ID from IAB Tech Lab sellers.json - **`tag_id`** *(optional)*: TAG Certified Against Fraud ID + - **`privacy_policy_url`** *(optional)*: URL to entity's privacy policy for consumer consent flows **`properties`** *(optional)*: Array of properties covered by this file (canonical property definitions) @@ -78,6 +79,14 @@ The file must be valid JSON with UTF-8 encoding and return HTTP 200 status. **`last_updated`** *(optional)*: ISO 8601 timestamp of last modification +**`property_features`** *(optional)*: Array of governance agents that provide data about properties in this file + - **`url`** *(required)*: Agent's API endpoint URL (governance agent implementing property governance tasks) + - **`name`** *(required)*: Human-readable name of the vendor/agent (e.g., "Scope3", "TAG", "OneTrust") + - **`features`** *(required)*: Array of feature IDs this agent provides (e.g., `["carbon_score", "gdpr_compliant"]`) + - **`publisher_id`** *(optional)*: Publisher's identifier at this agent (for lookup) + +This field enables **governance agent discovery** - buyers can find which agents have compliance, sustainability, or quality data for properties without querying every possible agent. + ## URL Reference Pattern For publishers with complex infrastructure or CDN distribution, `adagents.json` can reference an authoritative URL instead of containing the full structure inline. @@ -357,7 +366,8 @@ Large network using tags for grouping efficiency: "email": "adops@meta.com", "domain": "meta.com", "seller_id": "pub-meta-12345", - "tag_id": "12345" + "tag_id": "12345", + "privacy_policy_url": "https://www.meta.com/privacy/policy" }, "properties": [ { @@ -458,6 +468,121 @@ Different agents for different channels: } ``` +### 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 compliance, sustainability, and quality data. + +```json +{ + "$schema": "https://adcontextprotocol.org/schemas/v2/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-safe 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.scope3.com", + "name": "Scope3", + "features": ["carbon_score", "sustainability_grade"], + "publisher_id": "pub_news_12345" + }, + { + "url": "https://api.tagtoday.net", + "name": "TAG", + "features": ["tag_certified_against_fraud", "tag_brand_safety_certified"] + }, + { + "url": "https://api.onetrust.com", + "name": "OneTrust", + "features": ["gdpr_compliant", "tcf_registered", "ccpa_compliant"], + "publisher_id": "ot_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 +sequenceDiagram + participant Buyer as Buyer Agent + participant PubDomain as Publisher Domain + participant Scope3 as Scope3 Agent + participant OneTrust as OneTrust 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->>Scope3: list_property_features + Scope3-->>Buyer: Available features (carbon_score, etc.) + and + Buyer->>OneTrust: list_property_features + OneTrust-->>Buyer: Available features (gdpr_compliant, etc.) + end + + Note over Buyer: Create property lists on each governance agent + + Buyer->>Scope3: create_property_list(filters, brand_manifest) + Buyer->>OneTrust: create_property_list(filters, brand_manifest) +``` + +### When to Use property_features + +| Scenario | Use property_features? | +|----------|------------------------| +| Publisher has carbon scoring from Scope3 | ✅ Yes | +| Publisher is TAG certified | ✅ Yes | +| Publisher tracks consent via OneTrust | ✅ Yes | +| Publisher self-reports brand safety | ❌ 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 [list_property_features](/docs/governance/property/tasks/list_property_features#vendor-extensions) for details. + ## Fetching and Validating ### Using the AdAgents.json Builder @@ -620,14 +745,14 @@ The Python library handles validation automatically when fetching - if the adage After implementing adagents.json validation: -1. **Integrate with Product Discovery**: Use [`get_products`](../../media-buy/task-reference/get_products) to discover inventory -2. **Validate at Purchase**: Check authorization before calling [`create_media_buy`](../../media-buy/task-reference/create_media_buy) +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 -- [list_authorized_properties](../../media-buy/task-reference/list_authorized_properties) - Discover publisher domains an agent represents +- [list_authorized_properties](/docs/media-buy/task-reference/list_authorized_properties) - Discover publisher domains an agent represents - [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 diff --git a/docs/governance/property/index.mdx b/docs/governance/property/index.mdx index 674d1fc8f1..30e88882e5 100644 --- a/docs/governance/property/index.mdx +++ b/docs/governance/property/index.mdx @@ -11,20 +11,21 @@ Property Governance standardizes how advertising properties (websites, apps, CTV ## Overview -Property Governance addresses four distinct concerns: +Property Governance addresses five distinct concerns: | Concern | Question | Owner | Mechanism | |---------|----------|-------|-----------| | **Property Identity** | What properties exist? | Publishers | `adagents.json` properties array | | **Sales Authorization** | Who can sell this property? | Publishers | `adagents.json` authorized_agents | +| **Governance Agent Discovery** | Who has data about this property? | Publishers | `adagents.json` property_features | | **Property Data** | What do we know about this property? | Data providers | Governance agents via `list_property_features` | | **Property Selection** | Which properties meet my requirements? | Buyers | Property lists with filters | -The first two are **publisher-side declarations** via adagents.json. The last two are **buyer-side operations** that consume property data from governance agents. +The first three are **publisher-side declarations** via adagents.json. The last two are **buyer-side operations** that consume property data from governance agents. ## Publisher Side: adagents.json -Publishers declare their properties and authorize sales agents via `/.well-known/adagents.json`: +Publishers declare their properties, authorize sales agents, and reference governance agents via `/.well-known/adagents.json`: ```json { @@ -44,11 +45,43 @@ Publishers declare their properties and authorize sales agents via `/.well-known "authorization_type": "property_ids", "property_ids": ["example_site"] } + ], + "property_features": [ + { + "url": "https://api.scope3.com", + "name": "Scope3", + "features": ["carbon_score", "sustainability_grade"] + }, + { + "url": "https://api.onetrust.com", + "name": "OneTrust", + "features": ["gdpr_compliant", "tcf_registered"] + } ] } ``` -See the [adagents.json Tech Spec](./adagents) for complete documentation. +### Governance Agent Discovery via property_features + +The `property_features` array solves a key discovery problem: **how does a buyer know which governance agents have data about a given property?** + +Without `property_features`, buyers would need to query every possible governance agent to find out who has compliance, sustainability, or quality data. With `property_features`, publishers declare these relationships upfront: + +| Field | Purpose | +|-------|---------| +| `url` | Governance agent's API endpoint | +| `name` | Human-readable agent name (e.g., "Scope3", "TAG", "OneTrust") | +| `features` | Feature IDs this agent provides (e.g., `carbon_score`, `gdpr_compliant`) | +| `publisher_id` | Optional identifier for looking up this publisher at the agent | + +**Example use cases:** +- **Sustainability**: Publisher declares Scope3 tracks their carbon emissions +- **Compliance**: Publisher declares OneTrust manages their consent data +- **Certification**: Publisher declares TAG has verified their fraud prevention + +Buyers read `property_features` from adagents.json, then query only the relevant governance agents for detailed data. + +See the [adagents.json Tech Spec](/docs/governance/property/adagents) for complete documentation including examples and the discovery workflow. ## Buyer Side: Property Data and Selection @@ -113,8 +146,14 @@ A buyer agent typically works with **multiple governance agents** (consent, bran ```mermaid flowchart TB + subgraph Publisher["PUBLISHER (adagents.json)"] + P1["properties: identity"] + P2["authorized_agents: sales auth"] + P3["property_features: governance refs"] + end + subgraph Buyer["BUYER AGENT"] - B1[Source of truth for compliant list] + B1[Discovers governance agents from adagents.json] B2[Aggregates results from specialized agents] B3[Issues auth_tokens for sellers] end @@ -130,6 +169,7 @@ flowchart TB SE2[Uses cached lists for bid-time decisions] end + Publisher -->|property_features discovery| Buyer Buyer -->|create_property_list + webhooks| CA Buyer -->|create_property_list + webhooks| S3 Buyer -->|create_property_list + webhooks| BS @@ -137,59 +177,16 @@ flowchart TB Buyer -->|get_property_list with auth_token| Seller ``` -## Campaign Lifecycle - -Property governance operates across three distinct timing contexts. The key principle: **all governance evaluation happens at setup time**, with bid-time decisions using only cached data. - -```mermaid -sequenceDiagram - participant O as Orchestrator - participant G as Governance Agent - participant D as Decisioning Platform - - rect rgb(240, 248, 255) - Note over O,D: Phase 1: Campaign Planning (minutes-hours) - O->>G: create_property_list(filters, brand_manifest) - G-->>O: list_id, auth_token - O->>D: Share list_id + auth_token - D->>G: get_property_list(list_id, auth_token, resolve=true) - G-->>D: identifiers[] (pass/fail list, no scores) - D->>G: Register webhook for list updates - D->>D: Cache locally (optionally as AXE segments) - end - - rect rgb(255, 248, 240) - Note over O,D: Phase 2: Bid Time (under 100ms, NO governance calls) - D->>D: Check domain against cached allowlist - Note right of D: May use AXE axei/axex segments
or direct domain lookup - D->>D: Pass → bid, Fail → skip - end - - rect rgb(248, 255, 240) - Note over O,D: Phase 3: Monitoring (during flight) - G-->>D: Webhook: list changed (counts only) - D->>G: get_property_list(list_id, auth_token, resolve=true) - G-->>D: Updated identifiers[] - D->>D: Update cached allowlist - end -``` - -### Phase 1: Campaign Planning - -During campaign setup, the orchestrator creates property lists on governance agents with filters and brand manifests. The governance agent evaluates properties and returns a **pass/fail list of identifiers** (no raw scores are exposed). The orchestrator shares the `list_id` and `auth_token` with the decisioning platform, which fetches and caches the resolved list. - -### Phase 2: Bid Time - -At bid time, the decisioning platform uses **only its local cache**—no calls to governance agents. Latency requirements (under 100ms) make real-time API calls impractical. The decisioning platform may implement this cache as: - -- **Direct domain lookup**: In-memory set of approved domains -- **AXE segments**: Cache domains as `axei` (include) or `axex` (exclude) segments for impression-level filtering - -The choice of caching mechanism is implementation-specific; the protocol only requires that bid-time decisions use cached data. - -### Phase 3: Monitoring +### The Complete Flow -During campaign flight, governance agents continue evaluating properties. When a property's compliance status changes, the agent sends a webhook notification to registered subscribers. The webhook contains **change counts only** (not scores or reasons)—the decisioning platform must call `get_property_list` to fetch the updated list and refresh its cache. +1. **Publisher declares** properties, sales agents, AND governance agents in `adagents.json` +2. **Buyer discovers** governance agents by reading `property_features` from adagents.json +3. **Buyer queries** each governance agent's `list_property_features` for detailed capabilities +4. **Buyer creates** property lists on each governance agent with filters and brand manifests +5. **Governance agents evaluate** properties and notify buyer via webhooks when lists change +6. **Buyer aggregates** results into a final compliant list +7. **Buyer shares** property list reference with sellers (with auth token) +8. **Seller caches** resolved list for bid-time decisions ## Sharing Property Lists with Sellers @@ -251,31 +248,34 @@ Both protocols operate on properties but serve different purposes: ### Discovery -- **[list_property_features](./tasks/list_property_features)**: Discover what data a governance agent can provide about properties +- **[list_property_features](/docs/governance/property/tasks/list_property_features)**: Discover what data a governance agent can provide about properties ### Property List Management -- **[create_property_list](./tasks/property_lists#create_property_list)**: Create a new property list on a governance agent -- **[get_property_list](./tasks/property_lists#get_property_list)**: Retrieve resolved properties (with caching guidance) -- **[update_property_list](./tasks/property_lists#update_property_list)**: Modify filters or base properties -- **[delete_property_list](./tasks/property_lists#delete_property_list)**: Remove a property list +- **[create_property_list](/docs/governance/property/tasks/property_lists#create_property_list)**: Create a new property list on a governance agent +- **[get_property_list](/docs/governance/property/tasks/property_lists#get_property_list)**: Retrieve resolved properties (with caching guidance) +- **[update_property_list](/docs/governance/property/tasks/property_lists#update_property_list)**: Modify filters or base properties +- **[delete_property_list](/docs/governance/property/tasks/property_lists#delete_property_list)**: Remove a property list ## Getting Started **Publishers:** 1. Create `/.well-known/adagents.json` with property definitions 2. Authorize sales agents for your properties +3. Declare governance agents in `property_features` (Scope3 for carbon, OneTrust for consent, TAG for certification, etc.) **Buyers:** -1. Subscribe to governance agents for property data -2. Create property lists on each governance agent with filters and brand manifests -3. Aggregate results into a final compliant list -4. Share property list references with sellers (with auth tokens) +1. Discover governance agents by reading `property_features` from publishers' adagents.json files +2. Query each governance agent's `list_property_features` for capabilities +3. Create property lists on relevant governance agents with filters and brand manifests +4. Aggregate results into a final compliant list +5. Share property list references with sellers (with auth tokens) **Governance Agent Implementers:** 1. Implement `list_property_features` to advertise your capabilities 2. Implement property list CRUD operations 3. Support webhooks to notify buyers when evaluations change -4. See the [Protocol Specification](./specification) for implementation details +4. Work with publishers to get listed in their `property_features` +5. See the [Protocol Specification](/docs/governance/property/specification) for implementation details -See the [Protocol Specification](./specification) for detailed implementation guidance. +See the [Protocol Specification](/docs/governance/property/specification) for detailed implementation guidance. diff --git a/docs/governance/property/specification.mdx b/docs/governance/property/specification.mdx index 0d3e3e119c..15dee4fede 100644 --- a/docs/governance/property/specification.mdx +++ b/docs/governance/property/specification.mdx @@ -192,7 +192,7 @@ Discover what features a governance agent can evaluate. Create a new property list with filters and optional brand manifest. **Required Parameters**: -- At least one country in `countries_all` (ISO 3166-1 alpha-2 code, case-insensitive) +- At least one country in `countries_all` (ISO 3166-1 alpha-2 code) - At least one channel in `channels_any` (display, video, audio, etc.) **Base Properties**: An array of property sources to evaluate. Each entry is a discriminated union with `selection_type` as the discriminator: @@ -414,6 +414,36 @@ Orchestrators may consult multiple governance agents: ## Agent Discovery +There are two complementary discovery mechanisms: + +### Publisher-Side Discovery via adagents.json + +Publishers declare which governance agents have data about their properties using the `property_features` field in `adagents.json`: + +```json +{ + "property_features": [ + { + "url": "https://api.scope3.com", + "name": "Scope3", + "features": ["carbon_score", "sustainability_grade"], + "publisher_id": "pub_12345" + }, + { + "url": "https://api.onetrust.com", + "name": "OneTrust", + "features": ["gdpr_compliant", "tcf_registered", "ccpa_compliant"] + } + ] +} +``` + +This solves the discovery problem: buyers don't need to query every possible governance agent. Instead, they read `property_features` from the publisher's adagents.json to find which agents have relevant data. + +See the [adagents.json Tech Spec](/docs/governance/property/adagents#governance-agent-discovery) for the complete discovery workflow. + +### Agent-Side Discovery via agent-card.json + Governance agents expose capabilities via `.well-known/agent-card.json`: ```json @@ -444,6 +474,8 @@ Governance agents expose capabilities via `.well-known/agent-card.json`: } ``` +### Detailed Capability Discovery + Use `list_property_features` for detailed capability discovery: ```json @@ -605,7 +637,7 @@ Media buys can reference governance policies via property list references: ## Next Steps -- See the [adagents.json Tech Spec](./adagents) for property declaration and authorization -- See the [list_property_features task reference](./tasks/list_property_features) for capability discovery -- See the [Property List Management](./tasks/property_lists) for CRUD operations and webhooks -- See the [validate_property_delivery task reference](./tasks/validate_property_delivery) for post-campaign compliance validation +- See the [adagents.json Tech Spec](/docs/governance/property/adagents) for property declaration and authorization +- See the [list_property_features task reference](/docs/governance/property/tasks/list_property_features) for capability discovery +- See the [Property List Management](/docs/governance/property/tasks/property_lists) for CRUD operations and webhooks +- See the [validate_property_delivery task reference](/docs/governance/property/tasks/validate_property_delivery) for post-campaign compliance validation diff --git a/docs/governance/property/tasks/list_property_features.mdx b/docs/governance/property/tasks/list_property_features.mdx index 6c7dcd16a7..575ddeca3d 100644 --- a/docs/governance/property/tasks/list_property_features.mdx +++ b/docs/governance/property/tasks/list_property_features.mdx @@ -196,6 +196,29 @@ await a2a.send({ } ``` +## Vendor Extensions + +Feature definitions can include vendor-specific data in an `ext` block with vendor-namespaced fields: + +```json +{ + "feature_id": "carbon_score", + "name": "Carbon Emissions Score", + "type": "quantitative", + "range": { "min": 0, "max": 100 }, + "methodology_url": "https://scope3.com/methodology", + "ext": { + "scope3": { + "emissions_unit": "gCO2e_per_1000_impressions", + "model_version": "2024.1", + "sbti_aligned": true + } + } +} +``` + +Extensions are optional. Buyers should process features normally even if `ext` contains unfamiliar vendors. Each vendor's `methodology_url` documents their extension schema. + ## Integration Pattern Use `list_property_features` to understand agent capabilities before creating property lists: @@ -227,9 +250,38 @@ governance_agent.create_property_list( ) ``` +## Discovering Governance Agents + +Before calling `list_property_features`, you need to know which governance agents to query. There are two discovery mechanisms: + +### Via adagents.json (Publisher-Declared) + +Publishers declare which governance agents have data about their properties in `property_features` (from their `/.well-known/adagents.json`): + +```json +{ + "property_features": [ + { + "url": "https://api.scope3.com", + "name": "Scope3", + "features": ["carbon_score", "sustainability_grade"] + } + ] +} +``` + +This tells buyers: "Scope3 has carbon data for our properties." The buyer then calls `list_property_features` on Scope3 to get detailed feature definitions. + +See the [adagents.json Tech Spec](/docs/governance/property/adagents#governance-agent-discovery) for the complete discovery workflow. + +### Via Direct Subscription + +Buyers may also have direct relationships with governance agents (e.g., a subscription to a compliance vendor). In this case, the buyer already knows which agents to query. + ## Usage Notes -1. **Call first**: Use this task to discover capabilities before other governance tasks -2. **Cache results**: Feature definitions change infrequently; cache for hours/days -3. **Check coverage**: Not all features apply to all property types or countries -4. **Marketplace discovery**: Use this to understand what different governance agents offer +1. **Discover first**: Find governance agents via `property_features` in adagents.json before querying +2. **Call early**: Use this task to understand capabilities before other governance tasks +3. **Cache results**: Feature definitions change infrequently; cache for hours/days +4. **Check coverage**: Not all features apply to all property types or countries +5. **Marketplace discovery**: Use this to understand what different governance agents offer From 98858d3b53acd1368c6f3d4e1fd9051e9fbfbd36 Mon Sep 17 00:00:00 2001 From: Brian O'Kelley Date: Sat, 24 Jan 2026 10:21:05 -0500 Subject: [PATCH 30/34] feat: Add get_capabilities task for expanded capability discovery (#850) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: Add get_capabilities task for expanded capability discovery Introduces get_capabilities task replacing list_authorized_properties with expanded capability declaration for protocol versions, execution features, and portfolio information. Protocol section: - adcp_major_versions for compatibility - features (inline_creative_management, property_list_filtering, content_standards) Execution section: - axe_integrations for ad exchange support - creative_specs (VAST/MRAID versions) - targeting with granular geo support Geo targeting with named systems: - Metros: nielsen_dma, uk_itl1, uk_itl2, eurostat_nuts2 - Postal: us_zip, gb_outward, ca_fsa, etc. Product filters: - Added regions, metros, postal_areas filters - Added required_axe_integrations, required_features Capability contract: If declared, seller MUST honor it. Co-Authored-By: Claude Opus 4.5 * refactor: Move get_capabilities to protocol level for cross-protocol support Restructure get_capabilities as a protocol-level task that works across all AdCP domain protocols, not just media-buy. Response structure changes: - `adcp.major_versions` - AdCP version compatibility - `supported_protocols` - Which protocols this seller supports - `media_buy` section for media-buy specific capabilities - `signals` section reserved for future use This enables buyers to discover capabilities for all protocols in a single call, with protocol-specific details nested appropriately. Co-Authored-By: Claude Opus 4.5 * deprecate: Agent card extension in favor of tool-based discovery AdCP discovery now uses native MCP/A2A tool discovery: - Presence of 'get_capabilities' tool indicates AdCP support - Call get_capabilities for version, protocols, features, capabilities - No need for custom agent card extensions Deprecates adcp-extension.json - maintained for backward compatibility only. Co-Authored-By: Claude Opus 4.5 * rename: get_capabilities → get_adcp_capabilities for unambiguous discovery The distinctive name 'get_adcp_capabilities' ensures: - Immediate identification of AdCP support when scanning tool lists - No collision with other protocols' capability tools - Self-documenting tool presence Co-Authored-By: Claude Opus 4.5 * fix: Restore v2.6-rc directory after rebase The v2.6-rc directory was inadvertently modified during the cherry-pick rebase. Restoring from 2.6.x branch since this content is auto-generated. Co-Authored-By: Claude Opus 4.5 * feat: Add structured geo targeting with named systems - Update targeting.json: geo_metros and geo_postal_areas now use structured format with explicit system specification - Remove postal_areas from product-filters.json (too granular for product discovery; use metros for filtering, postal for execution) - Update get_adcp_capabilities docs to clarify: - Product filters use coarse geography (metros) - Targeting overlay uses fine-grained geography (postal areas) - Capability contract: if seller declares us_zip support, buyer can specify ZIP codes in create_media_buy targeting_overlay Co-Authored-By: Claude Opus 4.5 * feat: Add governance protocol support to get_adcp_capabilities Governance agents provide property data (compliance scores, brand safety ratings, sustainability metrics). Their capabilities are now declared in get_adcp_capabilities: - Added 'governance' to supported_protocols enum - Added governance.property_features array for feature definitions - Each feature has: feature_id, type (binary/quantitative/categorical), optional range/categories, description - Eliminates need for separate list_property_features task Co-Authored-By: Claude Opus 4.5 * deprecate: list_property_features in favor of get_adcp_capabilities - Remove list-property-features-request.json and response schemas - Update schema index.json to remove list_property_features entries - Update list_property_features.mdx with deprecation warning and migration guide - Update governance tasks index to reference get_adcp_capabilities for discovery - Update changeset to document the deprecation Governance agents now declare their capabilities via the property_features array in get_adcp_capabilities, eliminating the need for a separate discovery call. Co-Authored-By: Claude Opus 4.5 * feat: Add required_targeting_systems filter to product-filters Allows buyers to filter products to sellers that support specific targeting systems (e.g., 'us_zip', 'nielsen_dma') without passing actual geo values at discovery time. This enables the pattern: 1. Discovery: Filter by capability ("must support ZIP targeting") 2. Execution: Apply actual targeting ("deliver to these ZIP codes") Co-Authored-By: Claude Opus 4.5 * rename: required_targeting_systems → required_geo_systems Renamed for clarity and expanded to accept both: - Capability names: 'geo_countries', 'geo_regions' (boolean capabilities) - System names: 'us_zip', 'nielsen_dma' (nested system keys) Example: required_geo_systems: ['geo_regions', 'us_zip'] Filters to sellers supporting region targeting AND ZIP code targeting. Co-Authored-By: Claude Opus 4.5 * refactor: required_geo_targeting with two-layer structure Replaces flat `required_geo_systems` with structured `required_geo_targeting` that cleanly separates: - level: targeting granularity (country, region, metro, postal_area) - system: classification taxonomy (only for levels with multiple systems) Example: ```json { "required_geo_targeting": [ { "level": "region" }, { "level": "metro", "system": "nielsen_dma" }, { "level": "postal_area", "system": "us_zip" } ] } ``` This maps cleanly to capability checks: - { level: "region" } → targeting.geo_regions === true - { level: "metro", system: "nielsen_dma" } → targeting.geo_metros.nielsen_dma - { level: "postal_area", system: "us_zip" } → targeting.geo_postal_areas.us_zip Adds geo-level.json enum for the supported targeting levels. Co-Authored-By: Claude Opus 4.5 * refactor: Remove metros/regions from product filters Products don't have metro-specific coverage - they have country coverage. Product filters now use: - `countries` for coverage filtering - `required_geo_targeting` for capability discovery (what geo systems seller supports) Actual metro/region/postal values are used at targeting time in create_media_buy, not at product discovery time. Co-Authored-By: Claude Opus 4.5 * feat: Add regions/metros product filters for local inventory Two models for product geography: 1. **Coverage filters** (for locally-bound inventory): - `countries` - country coverage (all inventory) - `regions` - region coverage (ISO 3166-2) for regional OOH, local TV - `metros` - metro coverage ({ system, code }) for radio, DOOH, local TV Use when products ARE geographically bound (radio station = DMA) 2. **Capability filters** (for digital inventory with broad coverage): - `required_geo_targeting` - filter by seller capability Use when products have broad coverage and you'll target at buy time Co-Authored-By: Claude Opus 4.5 * feat: Add extensions_supported to get_adcp_capabilities response Allows agents to declare which extension namespaces they support. Buyers can expect meaningful data in ext.{namespace} fields from agents that declare support. Replaces extensions_supported from deprecated agent card extension. Co-Authored-By: Claude Opus 4.5 * feat: Add methodology_url to property_features Allows governance agents to link to documentation explaining how they calculate/measure a feature. Helps buyers understand and compare methodologies across different vendors. Co-Authored-By: Claude Opus 4.5 * docs: Update documentation to reference get_adcp_capabilities Replace references to deprecated list_authorized_properties with get_adcp_capabilities throughout documentation: - quickstart.mdx: Update auth section public operations - intro.mdx: Add capability discovery section - core-concepts.mdx: Update synchronous operations list - media-buy-quick-reference.mdx: Replace task reference section - mcp-guide.mdx: Add Protocol Tools section and discovery note - a2a-guide.mdx: Add to Available Skills and discovery note - security.mdx: Update low-risk operations and rate limits - authentication.mdx: Update public operations list - implementor-faq.mdx: Update property tag resolution guidance - adagents.mdx: Update Learn More link - authorized-properties.mdx: Update property tags workflow - get_products.mdx: Update code comments - testing.mdx: Update compliance checklist - capability-discovery/index.mdx: Mark deprecated task - task-reference/index.mdx: Add get_adcp_capabilities - media-buy/index.mdx: Add get_adcp_capabilities - governance/property/index.mdx: Reference get_adcp_capabilities Co-Authored-By: Claude Opus 4.5 * chore: remove empty changeset file Co-Authored-By: Claude Opus 4.5 --------- Co-authored-by: Claude Opus 4.5 --- .changeset/get-capabilities-task.md | 63 ++ docs/governance/property/adagents.mdx | 2 +- .../property/authorized-properties.mdx | 53 +- docs/governance/property/index.mdx | 22 +- docs/governance/property/tasks/index.mdx | 6 +- .../property/tasks/list_property_features.mdx | 163 ++---- docs/intro.mdx | 8 + docs/media-buy/advanced-topics/testing.mdx | 4 +- docs/media-buy/capability-discovery/index.mdx | 18 +- docs/media-buy/index.mdx | 10 +- .../media-buy/task-reference/get_products.mdx | 6 +- docs/media-buy/task-reference/index.mdx | 18 +- .../list_authorized_properties.mdx | 7 +- docs/protocol/get_adcp_capabilities.mdx | 548 ++++++++++++++++++ docs/protocols/a2a-guide.mdx | 9 +- docs/protocols/core-concepts.mdx | 2 +- docs/protocols/mcp-guide.mdx | 12 +- docs/quickstart.mdx | 2 +- docs/reference/authentication.mdx | 2 +- docs/reference/implementor-faq.mdx | 2 +- docs/reference/media-buy-quick-reference.mdx | 24 +- docs/reference/security.mdx | 6 +- .../schemas/source/core/product-filters.json | 63 +- static/schemas/source/core/targeting.json | 55 +- static/schemas/source/enums/geo-level.json | 13 + static/schemas/source/enums/metro-system.json | 14 + .../schemas/source/enums/postal-system.json | 18 + static/schemas/source/index.json | 45 +- .../list-property-features-request.json | 27 - .../list-property-features-response.json | 21 - .../get-adcp-capabilities-request.json | 24 + .../get-adcp-capabilities-response.json | 323 +++++++++++ .../source/protocols/adcp-extension.json | 20 +- 33 files changed, 1320 insertions(+), 290 deletions(-) create mode 100644 .changeset/get-capabilities-task.md create mode 100644 docs/protocol/get_adcp_capabilities.mdx create mode 100644 static/schemas/source/enums/geo-level.json create mode 100644 static/schemas/source/enums/metro-system.json create mode 100644 static/schemas/source/enums/postal-system.json delete mode 100644 static/schemas/source/property/list-property-features-request.json delete mode 100644 static/schemas/source/property/list-property-features-response.json create mode 100644 static/schemas/source/protocol/get-adcp-capabilities-request.json create mode 100644 static/schemas/source/protocol/get-adcp-capabilities-response.json diff --git a/.changeset/get-capabilities-task.md b/.changeset/get-capabilities-task.md new file mode 100644 index 0000000000..cb30a44bfa --- /dev/null +++ b/.changeset/get-capabilities-task.md @@ -0,0 +1,63 @@ +--- +"adcontextprotocol": minor +--- + +Add protocol-level get_adcp_capabilities task for cross-protocol capability discovery + +Introduces `get_adcp_capabilities` as a **protocol-level task** that works across all AdCP domain protocols. + +**Tool-based discovery:** +- AdCP discovery uses native MCP/A2A tool discovery +- Presence of `get_adcp_capabilities` tool indicates AdCP support +- Distinctive name ensures no collision with other protocols' capability tools +- Deprecates `adcp-extension.json` agent card extension + +**Cross-protocol design:** +- `adcp.major_versions` - Declare supported AdCP major versions +- `supported_protocols` - Which domain protocols are supported (media_buy, signals) +- `extensions_supported` - Extension namespaces this agent supports (e.g., `["scope3", "garm"]`) +- Protocol-specific capability sections nested under protocol name + +**Media-buy capabilities (media_buy section):** +- `features` - Optional features (inline_creative_management, property_list_filtering, content_standards) +- `execution.axe_integrations` - Agentic ad exchange URLs +- `execution.creative_specs` - VAST/MRAID version support +- `execution.targeting` - Geo targeting with granular system support +- `portfolio` - Publisher domains, channels, countries + +**Geo targeting:** +- Countries (ISO 3166-1 alpha-2) +- Regions (ISO 3166-2) +- Metros with named systems (nielsen_dma, uk_itl1, uk_itl2, eurostat_nuts2) +- Postal areas with named systems encoding country and precision (us_zip, gb_outward, ca_fsa, etc.) + +**Product filters - two models for geography:** + +*Coverage filters (for locally-bound inventory like radio, OOH, local TV):* +- `countries` - country coverage (ISO 3166-1 alpha-2) +- `regions` - region coverage (ISO 3166-2) for regional OOH, local TV +- `metros` - metro coverage ({ system, code }) for radio, DOOH, DMA-based inventory + +*Capability filters (for digital inventory with broad coverage):* +- `required_geo_targeting` - filter by seller capability with two-layer structure: + - `level`: targeting granularity (country, region, metro, postal_area) + - `system`: classification taxonomy (e.g., 'nielsen_dma', 'us_zip') +- `required_axe_integrations` - filter by AXE support +- `required_features` - filter by protocol feature support + +Use coverage filters when products ARE geographically bound (radio station = DMA). +Use capability filters when products have broad coverage and you'll target at buy time. + +**Targeting schema:** +- Updated `targeting.json` with structured geo systems +- `geo_metros` and `geo_postal_areas` now require system specification +- System names encode country and precision (us_zip, gb_outward, nielsen_dma, etc.) +- Aligns with capability declarations in get_adcp_capabilities + +**Governance capabilities (governance section):** +- `property_features` - Array of features this governance agent can evaluate +- Each feature has: `feature_id`, `type` (binary/quantitative/categorical), optional `range`/`categories` +- `methodology_url` - Optional URL to methodology documentation (helps buyers understand/compare vendor approaches) +- Deprecates `list_property_features` task (schemas removed, doc page retained with migration guide) + +**Capability contract:** If a capability is declared, the seller MUST honor it. diff --git a/docs/governance/property/adagents.mdx b/docs/governance/property/adagents.mdx index 84919e95da..7c94641d59 100644 --- a/docs/governance/property/adagents.mdx +++ b/docs/governance/property/adagents.mdx @@ -753,6 +753,6 @@ After implementing adagents.json validation: ## Learn More - [AdCP Basics: Authorized Properties](https://bokonads.com/p/adcp-basics-authorized-properties) - Accessible introduction to AdCP authorization -- [list_authorized_properties](/docs/media-buy/task-reference/list_authorized_properties) - Discover publisher domains an agent represents +- [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 diff --git a/docs/governance/property/authorized-properties.mdx b/docs/governance/property/authorized-properties.mdx index bd1e330028..5541e0a11c 100644 --- a/docs/governance/property/authorized-properties.mdx +++ b/docs/governance/property/authorized-properties.mdx @@ -34,7 +34,7 @@ AdCP faces similar challenges as AI agents begin to buy and sell advertising pro AdCP prevents unauthorized resale through a two-part system: 1. **Publisher Authorization**: Publishers explicitly authorize sales agents via `adagents.json` -2. **Agent Discovery**: Sales agents declare their authorized properties via `list_authorized_properties` +2. **Agent Discovery**: Sales agents declare their portfolio via [`get_adcp_capabilities`](/docs/protocol/get_adcp_capabilities) in the `media_buy.portfolio` section This creates a verifiable chain of authorization that buyer agents can validate. @@ -93,11 +93,15 @@ Publishers authorize sales agents by hosting an `adagents.json` file at `/.well- ## How Sales Agents Share Authorized Properties -Sales agents use the [`list_authorized_properties`](../../media-buy/task-reference/list_authorized_properties) task to declare all properties they are authorized to represent. This serves multiple purposes: +Sales agents use the [`get_adcp_capabilities`](/docs/protocol/get_adcp_capabilities) task to declare their portfolio information in the `media_buy.portfolio` section. This serves multiple purposes: -1. **Transparency**: Buyers can see what properties an agent represents -2. **Validation enablement**: Provides the data buyers need to verify authorization -3. **Tag resolution**: Enables efficient grouping of properties by tags +1. **Transparency**: Buyers can see what publishers an agent represents +2. **Validation enablement**: Provides publisher domains for buyers to verify authorization via `adagents.json` +3. **Portfolio overview**: Includes primary channels, countries, and portfolio description + + +The [`list_authorized_properties`](../../media-buy/task-reference/list_authorized_properties) task is deprecated. Use `get_adcp_capabilities` for portfolio information and fetch detailed property definitions from publisher `adagents.json` files. + ### Property Declaration Example @@ -143,8 +147,8 @@ Sales agents use the [`list_authorized_properties`](../../media-buy/task-referen For large networks representing thousands of properties, AdCP supports **property tags** to make the system manageable: - **Products** can reference `["local_radio", "midwest"]` instead of listing hundreds of stations -- **Buyers** use `list_authorized_properties` to resolve tags to actual properties -- **Authorization validation** works on the resolved properties +- **Buyers** use `get_adcp_capabilities` to discover the agent's portfolio and validate authorization +- **Authorization validation** works on the resolved properties via `adagents.json` ## Authorization Validation Workflow @@ -152,15 +156,15 @@ Here's how a buyer agent validates that a sales agent is authorized to represent ### 1. One-Time Setup ```javascript -// Get all properties the sales agent claims to represent -const response = await salesAgent.call('list_authorized_properties'); -const allProperties = response.properties; +// Get portfolio information from capabilities +const capabilities = await salesAgent.call('get_adcp_capabilities'); +const portfolio = capabilities.media_buy?.portfolio; +const publisherDomains = portfolio?.publisher_domains || []; -// For each unique publisher domain, fetch and cache adagents.json -const domains = [...new Set(allProperties.map(p => p.publisher_domain))]; +// For each publisher domain, fetch and cache adagents.json const authorizationCache = {}; -for (const domain of domains) { +for (const domain of publisherDomains) { try { const adagents = await fetch(`https://${domain}/.well-known/adagents.json`); authorizationCache[domain] = await adagents.json(); @@ -174,7 +178,8 @@ for (const domain of domains) { ### 2. Product Validation ```javascript // When evaluating a product -const product = await salesAgent.call('get_products', {brief: "Chicago radio ads"}); +const result = await salesAgent.call('get_products', {brief: "Chicago radio ads"}); +const product = result.products[0]; // Validate authorization for each publisher in publisher_properties const authorized = product.publisher_properties.every(pubProp => { @@ -183,19 +188,10 @@ const authorized = product.publisher_properties.every(pubProp => { if (!adagents) return false; // No adagents.json found - // Get properties from this publisher - const publisherProps = allProperties.filter(p => p.publisher_domain === domain); - - // Resolve property_tags to actual properties if needed - let propertiesToCheck = pubProp.property_ids - ? publisherProps.filter(p => pubProp.property_ids.includes(p.property_id)) - : publisherProps.filter(p => pubProp.property_tags.every(tag => p.tags.includes(tag))); - - // Validate authorization for these properties - return propertiesToCheck.every(property => - adagents.authorized_agents.some(agent => - agent.agent_id === salesAgent.id && - isCurrentlyAuthorized(agent.authorization_scope) + // Verify the sales agent is in publisher's authorized_agents + return adagents.authorized_agents.some(agent => + agent.url === salesAgent.url && + isAuthorizedForProperties(agent, pubProp) ); }); @@ -273,7 +269,8 @@ See the **[adagents.json Tech Spec](./adagents)** for complete implementation gu ## Related Documentation -- **[`list_authorized_properties`](../../media-buy/task-reference/list_authorized_properties)** - API reference for property discovery +- **[`get_adcp_capabilities`](/docs/protocol/get_adcp_capabilities)** - Discover agent capabilities and portfolio information +- **[`list_authorized_properties`](../../media-buy/task-reference/list_authorized_properties)** - Property discovery (deprecated - use `get_adcp_capabilities`) - **[Product Discovery](../../media-buy/product-discovery/)** - How authorization integrates with product discovery - **[Properties Schema](https://adcontextprotocol.org/schemas/v2/core/property.json)** - Technical property data model - **[adagents.json Tech Spec](./adagents)** - Complete `adagents.json` implementation guide \ No newline at end of file diff --git a/docs/governance/property/index.mdx b/docs/governance/property/index.mdx index 30e88882e5..6b01207c71 100644 --- a/docs/governance/property/index.mdx +++ b/docs/governance/property/index.mdx @@ -17,8 +17,7 @@ Property Governance addresses five distinct concerns: |---------|----------|-------|-----------| | **Property Identity** | What properties exist? | Publishers | `adagents.json` properties array | | **Sales Authorization** | Who can sell this property? | Publishers | `adagents.json` authorized_agents | -| **Governance Agent Discovery** | Who has data about this property? | Publishers | `adagents.json` property_features | -| **Property Data** | What do we know about this property? | Data providers | Governance agents via `list_property_features` | +| **Property Data** | What do we know about this property? | Data providers | Governance agents via [`get_adcp_capabilities`](/docs/protocol/get_adcp_capabilities) | | **Property Selection** | Which properties meet my requirements? | Buyers | Property lists with filters | The first three are **publisher-side declarations** via adagents.json. The last two are **buyer-side operations** that consume property data from governance agents. @@ -87,15 +86,17 @@ See the [adagents.json Tech Spec](/docs/governance/property/adagents) for comple ### Property Data Providers -Governance agents provide data about properties - compliance scores, brand safety ratings, sustainability metrics, etc. They advertise their capabilities via `list_property_features`: +Governance agents provide data about properties - compliance scores, brand safety ratings, sustainability metrics, etc. They advertise their capabilities via [`get_adcp_capabilities`](/docs/protocol/get_adcp_capabilities) in the `governance.property_features` section: ```json { - "features": [ - { "feature_id": "consent_quality", "type": "quantitative", "range": { "min": 0, "max": 100 } }, - { "feature_id": "coppa_certified", "type": "binary" }, - { "feature_id": "carbon_score", "type": "quantitative", "range": { "min": 0, "max": 100 } } - ] + "governance": { + "property_features": [ + { "feature_id": "consent_quality", "type": "quantitative", "range": { "min": 0, "max": 100 } }, + { "feature_id": "coppa_certified", "type": "binary" }, + { "feature_id": "carbon_score", "type": "quantitative", "range": { "min": 0, "max": 100 } } + ] + } } ``` @@ -248,7 +249,8 @@ Both protocols operate on properties but serve different purposes: ### Discovery -- **[list_property_features](/docs/governance/property/tasks/list_property_features)**: Discover what data a governance agent can provide about properties +- **[`get_adcp_capabilities`](/docs/protocol/get_adcp_capabilities)**: Discover governance capabilities including property features (protocol-level task) +- **[list_property_features](./tasks/list_property_features)**: Discover what data a governance agent can provide (deprecated - use `get_adcp_capabilities`) ### Property List Management @@ -272,7 +274,7 @@ Both protocols operate on properties but serve different purposes: 5. Share property list references with sellers (with auth tokens) **Governance Agent Implementers:** -1. Implement `list_property_features` to advertise your capabilities +1. Implement [`get_adcp_capabilities`](/docs/protocol/get_adcp_capabilities) to advertise your capabilities in `governance.property_features` 2. Implement property list CRUD operations 3. Support webhooks to notify buyers when evaluations change 4. Work with publishers to get listed in their `property_features` diff --git a/docs/governance/property/tasks/index.mdx b/docs/governance/property/tasks/index.mdx index 5b65fc4364..067a9301d1 100644 --- a/docs/governance/property/tasks/index.mdx +++ b/docs/governance/property/tasks/index.mdx @@ -15,7 +15,9 @@ Property governance uses a **stateful** model where all evaluation happens throu | Task | Purpose | Response Time | |------|---------|---------------| -| [list_property_features](./list_property_features) | Discover agent capabilities | ~200ms | +| [get_adcp_capabilities](/docs/protocol/get_adcp_capabilities) | Discover agent capabilities | ~200ms | + +Use the protocol-level `get_adcp_capabilities` task to discover what features a governance agent can evaluate. See the [governance section](/docs/protocol/get_adcp_capabilities#governance-protocol) for details on the `property_features` array. ## Property List Management @@ -92,7 +94,7 @@ Use `create_property_list` with filters and brand manifest: - `channels_any`: Property must support ANY of the listed channels - `feature_requirements`: Property must pass ALL requirements (AND) -Filters have two built-in fields (`countries_all`, `channels_any`) plus `feature_requirements` which reference features the agent provides (discovered via `list_property_features`). For quantitative features, use `min_value`/`max_value`. For binary or categorical features, use `allowed_values`. +Filters have two built-in fields (`countries_all`, `channels_any`) plus `feature_requirements` which reference features the agent provides (discovered via [`get_adcp_capabilities`](/docs/protocol/get_adcp_capabilities)). For quantitative features, use `min_value`/`max_value`. For binary or categorical features, use `allowed_values`. ### Getting Resolved Properties diff --git a/docs/governance/property/tasks/list_property_features.mdx b/docs/governance/property/tasks/list_property_features.mdx index 575ddeca3d..c24c1ccfa4 100644 --- a/docs/governance/property/tasks/list_property_features.mdx +++ b/docs/governance/property/tasks/list_property_features.mdx @@ -3,87 +3,15 @@ sidebar_position: 1 title: list_property_features --- - -**AdCP 3.0 Proposal** - This task is under development for AdCP 3.0. - + +**Deprecated** - Use [`get_adcp_capabilities`](/docs/protocol/get_adcp_capabilities) instead. Governance agent capabilities are now declared in the `governance.property_features` section of the capabilities response. + -**Task**: Discover what features a property governance agent can evaluate. +This task has been superseded by the protocol-level [`get_adcp_capabilities`](/docs/protocol/get_adcp_capabilities) task, which provides capability discovery across all AdCP protocols in a single call. -**Response Time**: ~200ms +## Migration -**Request Schema**: [`https://adcontextprotocol.org/schemas/v1/governance/list-property-features-request.json`](https://adcontextprotocol.org/schemas/v1/governance/list-property-features-request.json) -**Response Schema**: [`https://adcontextprotocol.org/schemas/v1/governance/list-property-features-response.json`](https://adcontextprotocol.org/schemas/v1/governance/list-property-features-response.json) - -The `list_property_features` task returns the features a governance agent can evaluate. This is the discovery mechanism for understanding an agent's capabilities before using other governance tasks. - -## Request Parameters - -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `property_types` | string[] | No | Filter to features available for these property types | -| `countries` | string[] | No | Filter to features available in these countries | - -## Response Structure - -All AdCP responses include: -- **message**: Human-readable summary of the operation result -- **context_id**: Session continuity identifier for follow-up requests -- **data**: Task-specific payload (see Response Data below) - -## Response Data - -```json -{ - "features": [ - { - "feature_id": "consent_quality", - "name": "Consent Quality Score", - "description": "Measures the quality of consent implementation including UX, granularity, and compliance", - "type": "quantitative", - "range": { "min": 0, "max": 100 }, - "coverage": { - "property_types": ["website", "mobile_app"], - "countries": [] - } - }, - { - "feature_id": "coppa_certified", - "name": "COPPA Certified", - "description": "Whether the property has COPPA certification for child-directed content", - "type": "binary", - "coverage": { - "property_types": ["website", "mobile_app", "ctv_app"], - "countries": ["US"] - } - }, - { - "feature_id": "content_category", - "name": "Content Category", - "description": "IAB content category classification", - "type": "categorical", - "allowed_values": ["news", "sports", "entertainment", "kids_family", "technology", "business", "adult", "violence"] - } - ] -} -``` - -### Feature Types - -| Type | Description | Schema Fields | -|------|-------------|---------------| -| `binary` | True/false values | None additional | -| `quantitative` | Numeric values within a range | `range: { min, max }` | -| `categorical` | Enumerated string values | `allowed_values: string[]` | - -### Coverage - -The `coverage` object indicates where a feature applies: -- **property_types**: Empty array means all property types -- **countries**: Empty array means all countries - -## Protocol-Specific Examples - -### MCP Request +Instead of calling `list_property_features`: ```json { @@ -92,67 +20,52 @@ The `coverage` object indicates where a feature applies: } ``` -### MCP Response +Call `get_adcp_capabilities` and access the `governance.property_features` array: ```json { - "message": "This agent evaluates 12 features across consent, brand safety, and sustainability.", - "context_id": "ctx-gov-features-123", - "features": [ - { - "feature_id": "consent_quality", - "name": "Consent Quality Score", - "description": "Measures the quality of consent implementation", - "type": "quantitative", - "range": { "min": 0, "max": 100 } - }, - { - "feature_id": "tcf_version", - "name": "TCF Version", - "description": "IAB Transparency & Consent Framework version supported", - "type": "categorical", - "allowed_values": ["none", "tcf_1.1", "tcf_2.0", "tcf_2.2"] - }, - { - "feature_id": "coppa_certified", - "name": "COPPA Certified", - "description": "Whether property has COPPA certification", - "type": "binary", - "coverage": { - "property_types": ["website", "mobile_app", "ctv_app"], - "countries": ["US"] - } - } - ] + "tool": "get_adcp_capabilities", + "arguments": {} } ``` -### MCP Request - Filtered by Property Type +Response: ```json { - "tool": "list_property_features", - "arguments": { - "property_types": ["mobile_app"] + "adcp": { "major_versions": [1] }, + "supported_protocols": ["governance"], + "governance": { + "property_features": [ + { + "feature_id": "consent_quality", + "type": "quantitative", + "range": { "min": 0, "max": 100 }, + "description": "Measures the quality of consent implementation" + }, + { + "feature_id": "coppa_certified", + "type": "binary", + "description": "Whether the property has COPPA certification" + }, + { + "feature_id": "content_category", + "type": "categorical", + "categories": ["news", "sports", "entertainment", "technology"], + "description": "IAB content category classification" + } + ] } } ``` -### A2A Request +## Feature Types -```javascript -await a2a.send({ - message: { - parts: [{ - kind: "data", - data: { - skill: "list_property_features", - parameters: {} - } - }] - } -}); -``` +| Type | Description | Schema Fields | +|------|-------------|---------------| +| `binary` | True/false values | None additional | +| `quantitative` | Numeric values within a range | `range: { min, max }` | +| `categorical` | Enumerated string values | `categories: string[]` | ## Example Feature Sets by Agent Type diff --git a/docs/intro.mdx b/docs/intro.mdx index ad41caa98a..712da3e8bd 100644 --- a/docs/intro.mdx +++ b/docs/intro.mdx @@ -260,6 +260,14 @@ AdCP's task-first architecture means you can access the same functionality throu - **Using A2A**: Perfect for complex workflows with approvals and multi-agent collaboration - **Protocol Agnostic**: Implementers write tasks once, support all protocols automatically +### Capability Discovery + +Every AdCP agent supports [`get_adcp_capabilities`](/docs/protocol/get_adcp_capabilities) as the primary entry point for discovering what the agent supports. This single call returns: +- Protocol versions and supported domains (media_buy, signals, governance) +- Portfolio information for sales agents +- Geo targeting capabilities and execution features +- Supported extensions for rich metadata + Learn more in the [Protocols section](/docs/protocols/getting-started). ## Next Steps diff --git a/docs/media-buy/advanced-topics/testing.mdx b/docs/media-buy/advanced-topics/testing.mdx index 3eb46502cf..90dc03a3ba 100644 --- a/docs/media-buy/advanced-topics/testing.mdx +++ b/docs/media-buy/advanced-topics/testing.mdx @@ -60,7 +60,7 @@ Addie can run comprehensive E2E tests including: **Standard Scenarios:** - **health_check** - Verify agent responds -- **discovery** - Test `get_products`, `list_creative_formats`, `list_authorized_properties` +- **discovery** - Test `get_adcp_capabilities`, `get_products`, `list_creative_formats` - **create_media_buy** - Discovery + create a test campaign - **full_sales_flow** - Complete lifecycle: create → update → delivery - **creative_sync** - Test `sync_creatives` flow @@ -83,9 +83,9 @@ By default tests run in dry-run mode. For real testing, ask Addie to run without Use this checklist to verify your sales agent implementation covers all required features: **Core Discovery (Required)** +- [ ] `get_adcp_capabilities` - Returns agent capabilities, portfolio, and supported features - [ ] `get_products` - Returns products with pricing_options, format_ids, delivery_type - [ ] `list_creative_formats` - Returns supported formats and creative agents -- [ ] `list_authorized_properties` - Returns publisher domains (if applicable) **Media Buy Lifecycle (Required)** - [ ] `create_media_buy` - Accepts packages with product_id, pricing_option_id, budget diff --git a/docs/media-buy/capability-discovery/index.mdx b/docs/media-buy/capability-discovery/index.mdx index 297984b4c1..a7249397f7 100644 --- a/docs/media-buy/capability-discovery/index.mdx +++ b/docs/media-buy/capability-discovery/index.mdx @@ -38,21 +38,25 @@ Learn how AdCP prevents unauthorized resale and ensures sales agents are legitim These capability discovery tasks provide the reference data needed for effective AdCP workflows: +### [`get_adcp_capabilities`](/docs/protocol/get_adcp_capabilities) +The primary capability discovery task. Returns protocol versions, supported features, portfolio information, and governance capabilities in a single call. Use this as your first interaction with any AdCP agent. + ### [`list_creative_formats`](/docs/media-buy/task-reference/list_creative_formats) Discover all supported creative formats with detailed specifications including dimensions, file types, duration limits, and technical requirements. -### [`list_authorized_properties`](/docs/media-buy/task-reference/list_authorized_properties) -Get all properties a sales agent is authorized to represent, including property tags for efficient organization and authorization validation data. +### [`list_authorized_properties`](/docs/media-buy/task-reference/list_authorized_properties) deprecated +Get all properties a sales agent is authorized to represent. **Deprecated** - use `get_adcp_capabilities` for portfolio information via the `media_buy.portfolio` section. ## Integration Pattern Capability discovery typically happens early in your AdCP workflow: -1. **Understand Formats**: Call [`list_creative_formats`](/docs/media-buy/task-reference/list_creative_formats) to learn supported creative types -2. **Validate Authorization**: Use [`list_authorized_properties`](/docs/media-buy/task-reference/list_authorized_properties) to verify sales agent legitimacy -3. **Discover Products**: Search for advertising inventory with [`get_products`](/docs/media-buy/task-reference/get_products) -4. **Plan Creatives**: Match discovered products to available formats for production planning -5. **Execute Campaigns**: Create media buys with confidence in format compatibility and authorization +1. **Discover Capabilities**: Call [`get_adcp_capabilities`](/docs/protocol/get_adcp_capabilities) to learn what the agent supports +2. **Understand Formats**: Call [`list_creative_formats`](/docs/media-buy/task-reference/list_creative_formats) to learn supported creative types +3. **Validate Authorization**: Check the `media_buy.portfolio` from capabilities, then verify via publisher `adagents.json` +4. **Discover Products**: Search for advertising inventory with [`get_products`](/docs/media-buy/task-reference/get_products) +5. **Plan Creatives**: Match discovered products to available formats for production planning +6. **Execute Campaigns**: Create media buys with confidence in format compatibility and authorization ## Why This Matters diff --git a/docs/media-buy/index.mdx b/docs/media-buy/index.mdx index 5afaa30219..31958f01e3 100644 --- a/docs/media-buy/index.mdx +++ b/docs/media-buy/index.mdx @@ -23,9 +23,10 @@ All protocols provide identical functionality - choose based on your integration The Media Buy protocol provides these essential operations: ### Discovery & Planning +- **[`get_adcp_capabilities`](/docs/protocol/get_adcp_capabilities)**: Discover agent capabilities, portfolio, and supported features (protocol-level) - **[`get_products`](/docs/media-buy/task-reference/get_products)**: Discover advertising inventory using natural language briefs - **[`list_creative_formats`](/docs/media-buy/task-reference/list_creative_formats)**: Understand creative requirements and specifications -- **[`list_authorized_properties`](/docs/media-buy/task-reference/list_authorized_properties)**: Verify publisher authorization and available properties +- **[`list_authorized_properties`](/docs/media-buy/task-reference/list_authorized_properties)**: Verify publisher authorization (deprecated - use `get_adcp_capabilities`) ### Campaign Execution - **[`create_media_buy`](/docs/media-buy/task-reference/create_media_buy)**: Launch advertising campaigns with complete lifecycle management @@ -223,9 +224,10 @@ Choose your path based on your role and needs: ### **For AI Agent Developers** 1. **Start with [Protocol Selection](/docs/protocols/protocol-comparison)** - Choose MCP or A2A based on your use case -2. **Learn [Capability Discovery](/docs/media-buy/capability-discovery/)** - Understand creative formats and property authorization -3. **Try [Product Discovery](/docs/media-buy/product-discovery/)** - See how natural language briefs work -4. **Reference [Task Reference](/docs/media-buy/task-reference/)** - Implement the 8 core tasks +2. **Call [`get_adcp_capabilities`](/docs/protocol/get_adcp_capabilities)** - Discover what the agent supports +3. **Learn [Capability Discovery](/docs/media-buy/capability-discovery/)** - Understand creative formats and property authorization +4. **Try [Product Discovery](/docs/media-buy/product-discovery/)** - See how natural language briefs work +5. **Reference [Task Reference](/docs/media-buy/task-reference/)** - Implement the core tasks ### **For Campaign Managers** 1. **Understand the [Media Buy Lifecycle](/docs/media-buy/media-buys/)** - Learn the complete workflow diff --git a/docs/media-buy/task-reference/get_products.mdx b/docs/media-buy/task-reference/get_products.mdx index 799b0fed8c..2280c722e7 100644 --- a/docs/media-buy/task-reference/get_products.mdx +++ b/docs/media-buy/task-reference/get_products.mdx @@ -357,7 +357,8 @@ const result = await testAgent.getProducts({ }); if (result.success && result.data) { - // Products with property_tags in publisher_properties need resolution via list_authorized_properties + // Products with property_tags in publisher_properties represent large networks + // Use get_adcp_capabilities to discover the agent's portfolio const productsWithTags = result.data.products.filter(p => p.publisher_properties?.some(pub => pub.property_tags && pub.property_tags.length > 0) ); @@ -379,7 +380,8 @@ async def discover_property_tags(): } ) - # Products with property_tags in publisher_properties need resolution via list_authorized_properties + # Products with property_tags in publisher_properties represent large networks + # Use get_adcp_capabilities to discover the agent's portfolio products_with_tags = [p for p in result.products if any(pub.get('property_tags') for pub in p.get('publisher_properties', []))] print(f"{len(products_with_tags)} products use property tags (large networks)") diff --git a/docs/media-buy/task-reference/index.mdx b/docs/media-buy/task-reference/index.mdx index df786fb95a..12f956cc67 100644 --- a/docs/media-buy/task-reference/index.mdx +++ b/docs/media-buy/task-reference/index.mdx @@ -16,7 +16,7 @@ Complete reference for all AdCP Media Buy tasks. Each task is designed for AI ag | [`create_media_buy`](/docs/media-buy/task-reference/create_media_buy) | Create campaigns from selected products | Minutes-Days | Media Buys | | [`update_media_buy`](/docs/media-buy/task-reference/update_media_buy) | Modify campaign settings and budgets | Minutes-Days | Media Buys | | [`list_creative_formats`](/docs/media-buy/task-reference/list_creative_formats) | View supported creative specifications | ~1s | Capability | -| [`list_authorized_properties`](/docs/media-buy/task-reference/list_authorized_properties) | See available publisher properties | ~1s | Capability | +| [`list_authorized_properties`](/docs/media-buy/task-reference/list_authorized_properties) | See available publisher properties (deprecated) | ~1s | Capability | | [`sync_creatives`](/docs/media-buy/task-reference/sync_creatives) | Upload and manage creative assets | Minutes-Days | Creatives | | [`list_creatives`](/docs/media-buy/task-reference/list_creatives) | Query creative library with filtering | ~1s | Creatives | | [`get_media_buy_delivery`](/docs/media-buy/task-reference/get_media_buy_delivery) | Retrieve performance and delivery data | ~60s | Reporting | @@ -28,7 +28,7 @@ AdCP tasks fall into four response time categories: ### 🟢 Instant (~1 second) **Simple database lookups** - [`list_creative_formats`](/docs/media-buy/task-reference/list_creative_formats) - Format specifications -- [`list_authorized_properties`](/docs/media-buy/task-reference/list_authorized_properties) - Available properties +- [`list_authorized_properties`](/docs/media-buy/task-reference/list_authorized_properties) - Available properties (deprecated - use [`get_adcp_capabilities`](/docs/protocol/get_adcp_capabilities)) - [`list_creatives`](/docs/media-buy/task-reference/list_creatives) - Creative library queries ### 🟡 Processing (~60 seconds) @@ -47,9 +47,10 @@ AdCP tasks fall into four response time categories: ### Discovery & Planning Start here to understand what's available and plan your campaign. +- **[`get_adcp_capabilities`](/docs/protocol/get_adcp_capabilities)** - Discover agent capabilities, portfolio, and supported features (protocol-level task) - **[`get_products`](/docs/media-buy/task-reference/get_products)** - The core discovery task using natural language briefs - **[`list_creative_formats`](/docs/media-buy/task-reference/list_creative_formats)** - Understand creative requirements -- **[`list_authorized_properties`](/docs/media-buy/task-reference/list_authorized_properties)** - See available placements +- **[`list_authorized_properties`](/docs/media-buy/task-reference/list_authorized_properties)** - See available placements (deprecated) ### Media Buy Management Create and manage your advertising campaigns. @@ -102,11 +103,12 @@ Long-running tasks provide: ## Getting Started -1. **Start with Discovery**: Use [`get_products`](/docs/media-buy/task-reference/get_products) to find relevant inventory -2. **Understand Formats**: Check [`list_creative_formats`](/docs/media-buy/task-reference/list_creative_formats) for requirements -3. **Create Campaign**: Use [`create_media_buy`](/docs/media-buy/task-reference/create_media_buy) with selected products -4. **Upload Creatives**: Use [`sync_creatives`](/docs/media-buy/task-reference/sync_creatives) for asset management -5. **Monitor Performance**: Track results with [`get_media_buy_delivery`](/docs/media-buy/task-reference/get_media_buy_delivery) +1. **Discover Capabilities**: Use [`get_adcp_capabilities`](/docs/protocol/get_adcp_capabilities) to understand what the agent supports +2. **Find Inventory**: Use [`get_products`](/docs/media-buy/task-reference/get_products) to find relevant inventory +3. **Understand Formats**: Check [`list_creative_formats`](/docs/media-buy/task-reference/list_creative_formats) for requirements +4. **Create Campaign**: Use [`create_media_buy`](/docs/media-buy/task-reference/create_media_buy) with selected products +5. **Upload Creatives**: Use [`sync_creatives`](/docs/media-buy/task-reference/sync_creatives) for asset management +6. **Monitor Performance**: Track results with [`get_media_buy_delivery`](/docs/media-buy/task-reference/get_media_buy_delivery) ## Related Documentation diff --git a/docs/media-buy/task-reference/list_authorized_properties.mdx b/docs/media-buy/task-reference/list_authorized_properties.mdx index ab8d2dad94..daff660aea 100644 --- a/docs/media-buy/task-reference/list_authorized_properties.mdx +++ b/docs/media-buy/task-reference/list_authorized_properties.mdx @@ -1,9 +1,14 @@ --- title: list_authorized_properties -sidebar_position: 1.5 +sidebar_position: 1.6 testable: true --- +:::warning Deprecated +`list_authorized_properties` is deprecated. Use [`get_adcp_capabilities`](/docs/protocol/get_adcp_capabilities) instead, which provides expanded capability declaration including protocol versions, execution features, and portfolio information. + +The portfolio fields from this task are available in the `media_buy.portfolio` section of `get_adcp_capabilities` response. +::: Discover which publishers a sales agent is authorized to represent. Returns publisher domains only - buyers fetch full property definitions from each publisher's adagents.json. diff --git a/docs/protocol/get_adcp_capabilities.mdx b/docs/protocol/get_adcp_capabilities.mdx new file mode 100644 index 0000000000..d6f8ecb9e6 --- /dev/null +++ b/docs/protocol/get_adcp_capabilities.mdx @@ -0,0 +1,548 @@ +--- +title: get_adcp_capabilities +sidebar_position: 1 +testable: false +--- + +Discover a seller's protocol support and capabilities across all AdCP protocols. This is the first call a buyer should make to understand what a seller supports. + +**Response Time**: ~2 seconds (configuration lookup) + +**Purpose**: +- **AdCP discovery** - Does this agent support AdCP? Which versions? +- **Protocol support** - Which domain protocols (media_buy, signals)? +- **Detailed capabilities** - Features, AXE integrations, geo targeting, portfolio + +**Request Schema**: [`/schemas/v1/protocol/get-adcp-capabilities-request.json`](https://adcontextprotocol.org/schemas/v1/protocol/get-adcp-capabilities-request.json) +**Response Schema**: [`/schemas/v1/protocol/get-adcp-capabilities-response.json`](https://adcontextprotocol.org/schemas/v1/protocol/get-adcp-capabilities-response.json) + +## Tool-Based Discovery + +AdCP uses native MCP/A2A tool discovery. **The presence of `get_adcp_capabilities` in an agent's tool list indicates AdCP support.** + +``` +Discovery Flow: +1. Browse agent's tool list (MCP) or skills (A2A) +2. See 'get_adcp_capabilities' tool → Agent supports AdCP +3. Call get_adcp_capabilities → Get version, protocols, features, capabilities +4. Proceed based on returned capabilities +``` + +This approach: +- Uses standard MCP/A2A mechanisms (no custom extensions) +- Always returns current capabilities (not stale metadata) +- Single source of truth for all capability information + +:::note +The agent card extension (`adcp-extension.json`) is deprecated. Use tool-based discovery instead. +::: + +## Request Parameters + +| Field | Type | Description | +|-------|------|-------------| +| `protocols` | string[] | Optional. Filter to specific protocols (`media_buy`, `signals`). If omitted, returns all supported protocols. | + +## Response Structure + +### adcp + +Core AdCP protocol information: + +| Field | Type | Description | +|-------|------|-------------| +| `major_versions` | integer[] | **Required.** AdCP major versions supported (e.g., `[1]`) | + +### supported_protocols + +Array of domain protocols this seller supports: + +```json +{ + "supported_protocols": ["media_buy"] +} +``` + +### media_buy + +Media-buy protocol capabilities. Only present if `media_buy` is in `supported_protocols`. + +#### features + +Optional media-buy features. **If declared true, seller MUST honor requests using that feature.** + +| Feature | Description | +|---------|-------------| +| `inline_creative_management` | Accepts creatives inline in `create_media_buy` requests | +| `property_list_filtering` | Honors `property_list` parameter in `get_products` | +| `content_standards` | Full support for content standards configuration | + +#### execution + +Technical execution capabilities: + +| Field | Type | Description | +|-------|------|-------------| +| `axe_integrations` | string[] | Agentic ad exchange (AXE) URLs this seller can execute through | +| `creative_specs` | object | Creative specification support (VAST versions, MRAID, etc.) | +| `targeting` | object | Targeting capabilities (geo granularity) | + +##### creative_specs + +| Field | Type | Description | +|-------|------|-------------| +| `vast_versions` | string[] | VAST versions supported (e.g., `["4.0", "4.1", "4.2"]`) | +| `mraid_versions` | string[] | MRAID versions supported | +| `vpaid` | boolean | VPAID support | +| `simid` | boolean | SIMID support | + +##### targeting + +| Field | Type | Description | +|-------|------|-------------| +| `geo_countries` | boolean | Country-level targeting using ISO 3166-1 alpha-2 codes | +| `geo_regions` | boolean | Region/state-level targeting using ISO 3166-2 codes (e.g., `US-NY`, `GB-SCT`) | +| `geo_metros` | object | Metro area targeting with system-specific support | +| `geo_postal_areas` | object | Postal area targeting with country and precision support | + +**geo_metros** specifies which metro classification systems are supported: + +| System | Description | +|--------|-------------| +| `nielsen_dma` | Nielsen DMA codes (US market, e.g., `501` for NYC) | +| `uk_itl1` | UK ITL Level 1 regions | +| `uk_itl2` | UK ITL Level 2 regions | +| `eurostat_nuts2` | Eurostat NUTS Level 2 regions (EU) | + +**geo_postal_areas** specifies which postal code systems are supported: + +| System | Description | +|--------|-------------| +| `us_zip` | US 5-digit ZIP codes (e.g., `10001`) | +| `us_zip_plus_four` | US 9-digit ZIP+4 codes (e.g., `10001-1234`) | +| `gb_outward` | UK postcode district (e.g., `SW1`, `EC1`) | +| `gb_full` | UK full postcode (e.g., `SW1A 1AA`) | +| `ca_fsa` | Canadian Forward Sortation Area (e.g., `K1A`) | +| `ca_full` | Canadian full postal code (e.g., `K1A 0B1`) | +| `de_plz` | German Postleitzahl (e.g., `10115`) | +| `fr_code_postal` | French code postal (e.g., `75001`) | +| `au_postcode` | Australian postcode (e.g., `2000`) | + +#### portfolio + +Inventory portfolio information: + +| Field | Type | Description | +|-------|------|-------------| +| `publisher_domains` | string[] | **Required.** Publisher domains this seller represents | +| `primary_channels` | string[] | Main advertising channels | +| `primary_countries` | string[] | Main countries (ISO codes) | +| `description` | string | Markdown portfolio description | +| `advertising_policies` | string | Content policies and restrictions | + +### signals + +Signals protocol capabilities. Only present if `signals` is in `supported_protocols`. Reserved for future use. + +### governance + +Governance protocol capabilities. Only present if `governance` is in `supported_protocols`. Governance agents provide property data like compliance scores, brand safety ratings, and sustainability metrics. + +#### property_features + +Array of property features this governance agent can evaluate: + +| Field | Type | Description | +|-------|------|-------------| +| `feature_id` | string | **Required.** Unique identifier (e.g., `consent_quality`, `coppa_certified`) | +| `type` | string | **Required.** Data type: `binary`, `quantitative`, or `categorical` | +| `range` | object | For quantitative: `{ min, max }` | +| `categories` | string[] | For categorical: valid values | +| `description` | string | Human-readable description | +| `methodology_url` | string | URL to methodology documentation | + +**Example governance agent response:** + +```json +{ + "adcp": { "major_versions": [1] }, + "supported_protocols": ["governance"], + "governance": { + "property_features": [ + { "feature_id": "consent_quality", "type": "quantitative", "range": { "min": 0, "max": 100 }, "description": "Quality score for consent collection practices", "methodology_url": "https://vendor.example.com/methodology/consent-quality" }, + { "feature_id": "coppa_certified", "type": "binary", "description": "COPPA compliance certification" }, + { "feature_id": "carbon_score", "type": "quantitative", "range": { "min": 0, "max": 100 }, "description": "Carbon footprint sustainability score", "methodology_url": "https://scope3.com/methodology/carbon-score" }, + { "feature_id": "content_category", "type": "categorical", "categories": ["news", "entertainment", "sports", "finance"], "description": "Primary content category" } + ] + } +} +``` + +### extensions_supported + +Array of extension namespaces this agent supports. Buyers can expect meaningful data in `ext.{namespace}` fields on responses from this agent. + +| Field | Type | Description | +|-------|------|-------------| +| `extensions_supported` | string[] | Extension namespaces (e.g., `["scope3", "garm"]`) | + +Extension schemas are published in the [AdCP extension registry](/docs/reference/extensions-and-context). When an agent declares support for an extension, buyers know to look for and process `ext.{namespace}` data in responses. + +**Example:** +```json +{ + "extensions_supported": ["scope3", "garm", "iab_tcf"] +} +``` + +This tells buyers: +- Product responses may include `ext.scope3` with Scope3 sustainability data +- Creative policies may include `ext.garm` with GARM brand safety categorizations +- Responses may include `ext.iab_tcf` with IAB TCF consent data + +## The Capability Contract + +**If a capability is declared, the seller MUST honor it.** + +- `media_buy.execution.targeting.geo_postal_areas.us_zip: true` → Buyer can send US ZIP codes, seller MUST target them +- `media_buy.execution.targeting.geo_metros.nielsen_dma: true` → Buyer can send DMA codes, seller MUST target them +- `media_buy.features.content_standards: true` → Seller MUST apply content standards when provided +- AXE URL in `media_buy.execution.axe_integrations` → Seller can execute through that exchange + +No silent ignoring. If a seller can't support a capability, they should declare `false` or omit it. + +## Common Scenarios + +### Basic Capability Discovery + +```javascript +import { AdcpClient } from '@adcp/client'; + +const client = new AdcpClient({ baseUrl: 'https://seller.example.com/mcp' }); + +// Get seller capabilities +const result = await client.getAdcpCapabilities({}); + +if (result.errors) { + throw new Error(`Request failed: ${result.errors[0].message}`); +} + +// Check protocol support +console.log(`AdCP versions: ${result.adcp.major_versions.join(', ')}`); +console.log(`Supported protocols: ${result.supported_protocols.join(', ')}`); + +// Check media-buy capabilities +if (result.supported_protocols.includes('media_buy')) { + const mediaBuy = result.media_buy; + + // Check feature support + if (mediaBuy.features?.content_standards) { + console.log('Content standards supported'); + } + + // Check AXE integrations + if (mediaBuy.execution?.axe_integrations?.includes('https://agentic.scope3.com')) { + console.log('Scope3 AXE integration available'); + } + + // Check geo targeting + if (mediaBuy.execution?.targeting?.geo_postal_areas?.us_zip) { + console.log('US ZIP code targeting supported'); + } + + // Portfolio overview + console.log(`Publishers: ${mediaBuy.portfolio.publisher_domains.length}`); + console.log(`Channels: ${mediaBuy.portfolio.primary_channels?.join(', ')}`); +} +``` + +### Filter Sellers by Capability + +```javascript +// Find sellers that support specific requirements +async function findCompatibleSellers(sellers, requirements) { + const compatible = []; + + for (const sellerUrl of sellers) { + const client = new AdcpClient({ baseUrl: sellerUrl }); + const caps = await client.getAdcpCapabilities({}); + + if (caps.errors) continue; + + // Must support media_buy protocol + if (!caps.supported_protocols.includes('media_buy')) continue; + + const mediaBuy = caps.media_buy; + + // Check AXE integration requirement + if (requirements.axeIntegration) { + if (!mediaBuy.execution?.axe_integrations?.includes(requirements.axeIntegration)) { + continue; + } + } + + // Check geo targeting requirement + if (requirements.postalCodeTargeting) { + if (!mediaBuy.execution?.targeting?.geo_postal_areas?.us_zip) { + continue; + } + } + + // Check feature requirement + if (requirements.contentStandards) { + if (!mediaBuy.features?.content_standards) { + continue; + } + } + + compatible.push({ url: sellerUrl, capabilities: caps }); + } + + return compatible; +} + +// Usage +const sellers = await findCompatibleSellers( + ['https://seller1.com/mcp', 'https://seller2.com/mcp'], + { + axeIntegration: 'https://agentic.scope3.com', + postalCodeTargeting: true, + contentStandards: true + } +); +``` + +### Use Capabilities to Build Targeting + +Capabilities tell you what you CAN specify in create_media_buy targeting. Use `required_geo_targeting` to filter products to sellers that support specific geo targeting levels and systems: + +```javascript +// First, check capabilities +const caps = await client.getAdcpCapabilities({}); + +if (!caps.supported_protocols.includes('media_buy')) { + throw new Error('Seller does not support media_buy protocol'); +} + +const mediaBuy = caps.media_buy; + +// Filter products to sellers with specific geo targeting capabilities +const products = await client.getProducts({ + brief: "Premium video inventory in US for ZIP-targeted campaign", + filters: { + channels: ['olv', 'ctv'], + countries: ['US'], + // Require seller supports ZIP targeting (capability filter - no actual ZIPs needed) + // level = granularity, system = classification taxonomy + required_geo_targeting: [ + { level: 'postal_area', system: 'us_zip' } + ], + // Only include if seller supports this AXE + required_axe_integrations: ['https://agentic.scope3.com'] + } +}); + +// Then, create media buy with fine-grained targeting +// (if seller supports postal areas, we can target specific ZIP codes) +const buy = await client.createMediaBuy({ + buyer_ref: 'my-campaign-001', + brand_manifest: { url: 'https://mybrand.com' }, + packages: [{ + buyer_ref: 'package-001', + product_id: products.products[0].product_id, + pricing_option_id: products.products[0].pricing_options[0].id, + budget: 10000, + // Targeting overlay refines delivery within product coverage + targeting_overlay: { + geo_countries: ['US'], + // Only specify ZIP targeting if seller supports it + ...(mediaBuy.execution?.targeting?.geo_postal_areas?.us_zip && { + geo_postal_areas: [{ + system: 'us_zip', + values: ['10001', '10002', '10003', '10004', '10005'] + }] + }) + } + }], + start_time: { type: 'asap' }, + end_time: '2025-03-01T00:00:00Z' +}); +``` + +**Two models for product geography:** + +| Inventory Type | Filter By | Example | +|----------------|-----------|---------| +| Digital (display, OLV, CTV) | Capability: `required_geo_targeting` | Products have broad coverage, target at buy time | +| Local (radio, DOOH, local TV) | Coverage: `metros`, `regions` | Products ARE geographically bound | + +- **Digital inventory**: Use `countries` + `required_geo_targeting` (capability), apply fine-grained targeting in `create_media_buy` +- **Local inventory**: Use `metros`/`regions` (coverage) to find products with coverage in your target markets + +### Local Inventory Example (Radio, DOOH) + +For locally-bound inventory, products ARE geographically specific. A radio station in NYC DMA only covers NYC. + +```javascript +// Find radio products in specific DMAs +const radioProducts = await client.getProducts({ + brief: "Radio inventory in NYC and LA markets", + filters: { + channels: ['radio'], + // Coverage filter: products must cover these metros + metros: [ + { system: 'nielsen_dma', code: '501' }, // NYC + { system: 'nielsen_dma', code: '803' } // LA + ] + } +}); + +// For local inventory, targeting_overlay is optional - +// the product's coverage IS the geography +const buy = await client.createMediaBuy({ + buyer_ref: 'radio-campaign-001', + brand_manifest: { url: 'https://mybrand.com' }, + packages: [{ + buyer_ref: 'package-001', + product_id: radioProducts.products[0].product_id, + pricing_option_id: radioProducts.products[0].pricing_options[0].id, + budget: 5000 + // No targeting_overlay needed - product covers NYC DMA + }], + start_time: { type: 'asap' }, + end_time: '2025-03-01T00:00:00Z' +}); +``` + +## Response Example + +```json +{ + "adcp": { + "major_versions": [1] + }, + "supported_protocols": ["media_buy"], + "media_buy": { + "features": { + "inline_creative_management": true, + "property_list_filtering": true, + "content_standards": false + }, + "execution": { + "axe_integrations": ["https://agentic.scope3.com"], + "creative_specs": { + "vast_versions": ["4.0", "4.1", "4.2"], + "mraid_versions": ["3.0"], + "vpaid": false, + "simid": true + }, + "targeting": { + "geo_countries": true, + "geo_regions": true, + "geo_metros": { + "nielsen_dma": true, + "uk_itl2": false, + "eurostat_nuts2": false + }, + "geo_postal_areas": { + "us_zip": true, + "us_zip_plus_four": false, + "gb_outward": true, + "gb_full": false, + "ca_fsa": true + } + } + }, + "portfolio": { + "publisher_domains": ["example.com", "news.example.com"], + "primary_channels": ["display", "olv"], + "primary_countries": ["US", "CA"] + } + }, + "extensions_supported": ["scope3"], + "last_updated": "2025-01-23T10:00:00Z" +} +``` + +This tells buyers: +- **AdCP versions**: Version 1 +- **Protocols**: Media-buy only (signals not supported) +- **Country targeting**: Available (ISO 3166-1 alpha-2: `US`, `GB`, etc.) +- **Region targeting**: Available (ISO 3166-2: `US-NY`, `GB-SCT`, etc.) +- **Metro targeting**: Nielsen DMA only (US market) +- **Postal targeting**: US ZIP, UK outward codes, Canadian FSA +- **Extensions**: Scope3 sustainability data in `ext.scope3` + +### Geo Standards Reference + +| Level | System | Examples | +|-------|--------|----------| +| Country | ISO 3166-1 alpha-2 | `US`, `GB`, `DE`, `CA` | +| Region | ISO 3166-2 | `US-NY`, `GB-SCT`, `DE-BY`, `CA-ON` | +| Metro (US) | `nielsen_dma` | `501` (NYC), `803` (LA), `602` (Chicago) | +| Metro (UK) | `uk_itl2` | `UKI` (London), `UKD` (North West) | +| Metro (EU) | `eurostat_nuts2` | `DE30` (Berlin), `FR10` (Île-de-France) | +| Postal (US) | `us_zip` | `10001`, `90210` | +| Postal (US) | `us_zip_plus_four` | `10001-1234` | +| Postal (UK) | `gb_outward` | `SW1`, `EC1`, `M1` | +| Postal (UK) | `gb_full` | `SW1A 1AA` | +| Postal (CA) | `ca_fsa` | `K1A`, `M5V` | + +## Migration from list_authorized_properties + +If migrating from `list_authorized_properties`: + +| Old Field | New Location | +|-----------|--------------| +| `publisher_domains` | `media_buy.portfolio.publisher_domains` | +| `primary_channels` | `media_buy.portfolio.primary_channels` | +| `primary_countries` | `media_buy.portfolio.primary_countries` | +| `portfolio_description` | `media_buy.portfolio.description` | +| `advertising_policies` | `media_buy.portfolio.advertising_policies` | +| `last_updated` | `last_updated` (top level) | + +New fields: +- `adcp.major_versions` - Version compatibility +- `supported_protocols` - Which domain protocols are supported +- `media_buy.features` - Optional feature support +- `media_buy.execution.axe_integrations` - Ad exchange support +- `media_buy.execution.creative_specs` - VAST/MRAID versions +- `media_buy.execution.targeting` - Geo targeting granularity + +## Error Handling + +| Error Code | Description | Resolution | +|------------|-------------|------------| +| `AUTH_REQUIRED` | Authentication needed | Provide credentials | +| `INTERNAL_ERROR` | Server error | Retry with backoff | + +## Best Practices + +**1. Cache Capabilities** +Capabilities rarely change. Cache results and use `last_updated` for staleness detection. + +**2. Check Protocol Support First** +Before accessing protocol-specific fields, verify the protocol is in `supported_protocols`. + +**3. Check Before Requesting** +Don't send postal areas for a system the seller doesn't support. Don't request features the seller doesn't support. + +**4. Fail Fast on Incompatibility** +If a seller doesn't support required capabilities, skip them early rather than discovering failures later. + +**5. Use Protocol Version for Routing** +Route requests to appropriate API versions based on `adcp.major_versions`. + +## Next Steps + +After discovering capabilities: + +1. **Filter products**: Use [`get_products`](/docs/media-buy/task-reference/get_products) with capability-aware filters +2. **Validate properties**: Fetch publisher `adagents.json` files for property definitions +3. **Create buys**: Use [`create_media_buy`](/docs/media-buy/task-reference/create_media_buy) with supported features + +## Learn More + +- [adagents.json Specification](/docs/governance/property/adagents) - Publisher authorization files +- [Product Filters](/docs/media-buy/task-reference/get_products#filters) - Capability-aware filtering +- [Content Standards](/docs/governance/content-standards) - Brand safety configuration diff --git a/docs/protocols/a2a-guide.mdx b/docs/protocols/a2a-guide.mdx index f66867dc49..f01e2912e9 100644 --- a/docs/protocols/a2a-guide.mdx +++ b/docs/protocols/a2a-guide.mdx @@ -673,7 +673,8 @@ await a2a.send({ ``` ### Available Skills -- **Media Buy**: `get_products`, `list_creative_formats`, `create_media_buy`, `update_media_buy`, `sync_creatives`, `get_media_buy_delivery`, `list_authorized_properties`, `provide_performance_feedback` +- **Protocol**: `get_adcp_capabilities` (start here to discover agent capabilities) +- **Media Buy**: `get_products`, `list_creative_formats`, `create_media_buy`, `update_media_buy`, `sync_creatives`, `get_media_buy_delivery`, `provide_performance_feedback` - **Signals**: `get_signals`, `activate_signal` **Task Parameters**: See [Media Buy](/docs/media-buy) and [Signals](/docs/signals/overview) documentation for complete parameter specifications. @@ -728,7 +729,11 @@ console.log('Examples:', getProductsSkill.examples); ### AdCP Extension -**Recommended**: Include the AdCP extension in your agent card's `extensions` array to declare AdCP support programmatically. + +**Recommended**: Use [`get_adcp_capabilities`](/docs/protocol/get_adcp_capabilities) for runtime capability discovery. The agent card extension provides static metadata for agent registries and discovery services. + + +Include the AdCP extension in your agent card's `extensions` array to declare AdCP support programmatically. The A2A protocol uses an `extensions` array where each extension has: - **`uri`**: Extension identifier (use `https://adcontextprotocol.org/extensions/adcp`) diff --git a/docs/protocols/core-concepts.mdx b/docs/protocols/core-concepts.mdx index dfebab3af2..dbe24b6e2b 100644 --- a/docs/protocols/core-concepts.mdx +++ b/docs/protocols/core-concepts.mdx @@ -164,7 +164,7 @@ Async operations start with `working` and provide updates: AdCP operations fall into three categories: 1. **Synchronous** - Return immediately with `completed` or `failed` - - `list_creative_formats`, `list_authorized_properties` + - `get_adcp_capabilities`, `list_creative_formats` - Fast operations that don't require external systems 2. **Interactive** - May return `input-required` before proceeding diff --git a/docs/protocols/mcp-guide.mdx b/docs/protocols/mcp-guide.mdx index a8581b776e..6a9f11d5f3 100644 --- a/docs/protocols/mcp-guide.mdx +++ b/docs/protocols/mcp-guide.mdx @@ -92,15 +92,19 @@ MCP responses use a **flat structure** where task-specific fields are at the top All AdCP tasks are available as MCP tools: +### Protocol Tools +```javascript +await mcp.call('get_adcp_capabilities', {...}); // Discover agent capabilities (start here) +``` + ### Media Buy Tools ```javascript await mcp.call('get_products', {...}); // Discover inventory await mcp.call('list_creative_formats', {...}); // Get format specs -await mcp.call('create_media_buy', {...}); // Create campaigns +await mcp.call('create_media_buy', {...}); // Create campaigns await mcp.call('update_media_buy', {...}); // Modify campaigns await mcp.call('sync_creatives', {...}); // Manage creative assets await mcp.call('get_media_buy_delivery', {...}); // Performance metrics -await mcp.call('list_authorized_properties', {...}); // Available properties await mcp.call('provide_performance_feedback', {...}); // Share outcomes ``` @@ -634,6 +638,10 @@ const adcpTools = tools.filter(t => t.name.startsWith('adcp_') || ### AdCP Extension via MCP Server Card + +**Recommended**: Use [`get_adcp_capabilities`](/docs/protocol/get_adcp_capabilities) for runtime capability discovery. The server card extension provides static metadata for tool catalogs and registries. + + MCP servers can declare AdCP support via a server card at `/.well-known/mcp.json` (or `/.well-known/server.json`). AdCP-specific metadata goes in the `_meta` field using the `adcontextprotocol.org` namespace. ```json diff --git a/docs/quickstart.mdx b/docs/quickstart.mdx index ade7a90c3e..efef9f25f7 100644 --- a/docs/quickstart.mdx +++ b/docs/quickstart.mdx @@ -109,8 +109,8 @@ Now that you've seen basic product discovery, explore: ## Understanding Authentication Some operations work without credentials: +- `get_adcp_capabilities` - Discover agent capabilities - `list_creative_formats` - Browse creative formats -- `list_authorized_properties` - See publisher properties - `get_products` - Discover inventory (limited results) Most operations require authentication: diff --git a/docs/reference/authentication.mdx b/docs/reference/authentication.mdx index 0f1e4aafa4..2324b8aa58 100644 --- a/docs/reference/authentication.mdx +++ b/docs/reference/authentication.mdx @@ -12,8 +12,8 @@ AdCP uses a tiered authentication model where some operations are publicly acces These operations work without credentials to enable discovery and evaluation: +- **`get_adcp_capabilities`** - Discover agent capabilities, portfolio, and supported features - **`list_creative_formats`** - Browse available creative formats -- **`list_authorized_properties`** - See which properties an agent represents - **`get_products`** - Discover inventory (returns limited results without auth) **Rationale**: Publishers want potential buyers to discover their capabilities before establishing a business relationship. diff --git a/docs/reference/implementor-faq.mdx b/docs/reference/implementor-faq.mdx index 747ada9c0c..0b73197b03 100644 --- a/docs/reference/implementor-faq.mdx +++ b/docs/reference/implementor-faq.mdx @@ -213,7 +213,7 @@ Best practice: Always require it. Policy checking should happen during discovery } ``` -Buyers resolve tags via `list_authorized_properties`. This keeps responses lightweight while maintaining full validation capability. +Buyers can discover the agent's portfolio via [`get_adcp_capabilities`](/docs/protocol/get_adcp_capabilities), which returns the publisher domains and primary channels the agent represents. This keeps responses lightweight while maintaining full validation capability. ## Testing and Validation diff --git a/docs/reference/media-buy-quick-reference.mdx b/docs/reference/media-buy-quick-reference.mdx index 65d2a3b4fc..a655efee52 100644 --- a/docs/reference/media-buy-quick-reference.mdx +++ b/docs/reference/media-buy-quick-reference.mdx @@ -10,8 +10,8 @@ Use the `call_adcp_agent` tool to execute these tasks against any AdCP sales age | Task | Purpose | Response Time | |------|---------|---------------| +| `get_adcp_capabilities` | Discover agent capabilities and portfolio | ~1s | | `get_products` | Discover inventory using natural language | ~60s | -| `list_authorized_properties` | See publisher properties | ~1s | | `list_creative_formats` | View creative specifications | ~1s | | `create_media_buy` | Create campaigns | Minutes-Days | | `update_media_buy` | Modify campaigns | Minutes-Days | @@ -21,11 +21,12 @@ Use the `call_adcp_agent` tool to execute these tasks against any AdCP sales age ## Typical Workflow -1. **Discover products**: `get_products` with a natural language brief -2. **Review formats**: `list_creative_formats` to understand creative requirements -3. **Create campaign**: `create_media_buy` with selected products and budget -4. **Upload creatives**: `sync_creatives` to add creative assets -5. **Monitor delivery**: `get_media_buy_delivery` to track performance +1. **Discover capabilities**: `get_adcp_capabilities` to understand what the agent supports +2. **Discover products**: `get_products` with a natural language brief +3. **Review formats**: `list_creative_formats` to understand creative requirements +4. **Create campaign**: `create_media_buy` with selected products and budget +5. **Upload creatives**: `sync_creatives` to add creative assets +6. **Monitor delivery**: `get_media_buy_delivery` to track performance --- @@ -59,9 +60,9 @@ Discover advertising products using natural language briefs. --- -### list_authorized_properties +### get_adcp_capabilities -Get the list of publisher properties this agent can sell. +Discover agent capabilities, portfolio, and supported features. **Start here** when working with a new agent. ```json {} @@ -70,7 +71,12 @@ Get the list of publisher properties this agent can sell. No parameters required. **Response contains:** -- `publisher_domains`: Array of domain strings the agent is authorized to sell +- `adcp.major_versions`: Supported AdCP versions +- `supported_protocols`: Which protocols the agent implements (media_buy, signals, governance) +- `media_buy.portfolio`: Publisher domains, primary channels, and countries +- `media_buy.execution`: Geo targeting capabilities and AXE integrations + +See [get_adcp_capabilities](/docs/protocol/get_adcp_capabilities) for complete documentation. --- diff --git a/docs/reference/security.mdx b/docs/reference/security.mdx index 74b01e63de..1f138708ed 100644 --- a/docs/reference/security.mdx +++ b/docs/reference/security.mdx @@ -119,9 +119,9 @@ These operations are publicly accessible to enable discovery: | Operation | Risk | Auth Required | |-----------|------|---------------| +| `get_adcp_capabilities` | Agent capability discovery | None | | `get_products` | Public inventory discovery | Optional (limited results without auth) | | `list_creative_formats` | Public format catalog | None | -| `list_authorized_properties` | Public property listing | None | ## Authentication & Authorization @@ -167,7 +167,7 @@ AdCP implementations should implement fine-grained authorization: | Scope | Description | Example Operations | |-------|-------------|-------------------| -| `read:products` | Discover available inventory | `get_products`, `list_creative_formats`, `list_authorized_properties` | +| `read:products` | Discover available inventory | `get_adcp_capabilities`, `get_products`, `list_creative_formats` | | `read:campaigns` | View campaign details | `list_creatives`, `get_media_buy_delivery` | | `write:campaigns` | Create and modify campaigns | `create_media_buy`, `update_media_buy` | | `read:creatives` | Preview and inspect creatives | `preview_creative` | @@ -960,9 +960,9 @@ Implement multi-tiered rate limiting to prevent abuse while allowing legitimate ```typescript const RATE_LIMITS = { // Discovery tasks (read-only, cacheable) + 'get_adcp_capabilities': { requests: 100, window: '1m' }, 'get_products': { requests: 100, window: '1m' }, 'list_creative_formats': { requests: 100, window: '1m' }, - 'list_authorized_properties': { requests: 100, window: '1m' }, // Campaign management (state-changing, expensive) 'create_media_buy': { requests: 10, window: '1m' }, diff --git a/static/schemas/source/core/product-filters.json b/static/schemas/source/core/product-filters.json index 492ffcee08..20aa1daa6f 100644 --- a/static/schemas/source/core/product-filters.json +++ b/static/schemas/source/core/product-filters.json @@ -84,18 +84,79 @@ }, "countries": { "type": "array", - "description": "Filter by target countries using ISO 3166-1 alpha-2 country codes (e.g., ['US', 'CA', 'GB'])", + "description": "Filter by country coverage using ISO 3166-1 alpha-2 codes (e.g., ['US', 'CA', 'GB']). Works for all inventory types.", "items": { "type": "string", "pattern": "^[A-Z]{2}$" } }, + "regions": { + "type": "array", + "description": "Filter by region coverage using ISO 3166-2 codes (e.g., ['US-NY', 'US-CA', 'GB-SCT']). Use for locally-bound inventory (regional OOH, local TV) where products have region-specific coverage.", + "items": { + "type": "string", + "pattern": "^[A-Z]{2}-[A-Z0-9]+$" + } + }, + "metros": { + "type": "array", + "description": "Filter by metro coverage for locally-bound inventory (radio, DOOH, local TV). Use when products have DMA/metro-specific coverage. For digital inventory where products have broad coverage, use required_geo_targeting instead to filter by seller capability.", + "items": { + "type": "object", + "properties": { + "system": { + "$ref": "/schemas/enums/metro-system.json", + "description": "Metro classification system" + }, + "code": { + "type": "string", + "description": "Metro code within the system (e.g., '501' for NYC DMA)" + } + }, + "required": ["system", "code"], + "additionalProperties": false + } + }, "channels": { "type": "array", "description": "Filter by advertising channels (e.g., ['display', 'video', 'dooh'])", "items": { "$ref": "/schemas/enums/channels.json" } + }, + "required_axe_integrations": { + "type": "array", + "description": "Filter to products executable through specific agentic ad exchanges. URLs are canonical identifiers.", + "items": { + "type": "string", + "format": "uri" + } + }, + "required_features": { + "type": "array", + "description": "Filter to products from sellers supporting specific protocol features (e.g., 'content_standards', 'inline_creative_management')", + "items": { + "type": "string" + } + }, + "required_geo_targeting": { + "type": "array", + "description": "Filter to products from sellers supporting specific geo targeting capabilities. Each entry specifies a targeting level (country, region, metro, postal_area) and optionally a system for levels that have multiple classification systems.", + "items": { + "type": "object", + "properties": { + "level": { + "$ref": "/schemas/enums/geo-level.json", + "description": "Geographic targeting level (country, region, metro, postal_area)" + }, + "system": { + "type": "string", + "description": "Classification system within the level. Required for metro (e.g., 'nielsen_dma') and postal_area (e.g., 'us_zip'). Not applicable for country/region which use ISO standards." + } + }, + "required": ["level"], + "additionalProperties": false + } } }, "additionalProperties": true diff --git a/static/schemas/source/core/targeting.json b/static/schemas/source/core/targeting.json index f2f6972057..a3adfc74f0 100644 --- a/static/schemas/source/core/targeting.json +++ b/static/schemas/source/core/targeting.json @@ -5,33 +5,66 @@ "description": "Optional geographic refinements for media buys. Most targeting should be expressed in the brief and handled by the publisher. These fields are primarily for geographic restrictions (RCT testing, regulatory compliance).", "type": "object", "properties": { - "geo_country_any_of": { + "geo_countries": { "type": "array", - "description": "Restrict delivery to specific countries (ISO codes). Use for regulatory compliance or RCT testing.", + "description": "Restrict delivery to specific countries. ISO 3166-1 alpha-2 codes (e.g., 'US', 'GB', 'DE').", "items": { "type": "string", "pattern": "^[A-Z]{2}$" } }, - "geo_region_any_of": { + "geo_regions": { "type": "array", - "description": "Restrict delivery to specific regions/states. Use for regulatory compliance or RCT testing.", + "description": "Restrict delivery to specific regions/states. ISO 3166-2 subdivision codes (e.g., 'US-CA', 'GB-SCT').", "items": { - "type": "string" + "type": "string", + "pattern": "^[A-Z]{2}-[A-Z0-9]{1,3}$" } }, - "geo_metro_any_of": { + "geo_metros": { "type": "array", - "description": "Restrict delivery to specific metro areas (DMA codes). Use for regulatory compliance or RCT testing.", + "description": "Restrict delivery to specific metro areas. Each entry specifies the classification system and target values. Seller must declare supported systems in get_adcp_capabilities.", "items": { - "type": "string" + "type": "object", + "properties": { + "system": { + "$ref": "/schemas/enums/metro-system.json", + "description": "Metro area classification system (e.g., 'nielsen_dma', 'uk_itl2')" + }, + "values": { + "type": "array", + "description": "Metro codes within the system (e.g., ['501', '602'] for Nielsen DMAs)", + "items": { + "type": "string" + }, + "minItems": 1 + } + }, + "required": ["system", "values"], + "additionalProperties": false } }, - "geo_postal_code_any_of": { + "geo_postal_areas": { "type": "array", - "description": "Restrict delivery to specific postal/ZIP codes. Use for regulatory compliance or RCT testing.", + "description": "Restrict delivery to specific postal areas. Each entry specifies the postal system and target values. Seller must declare supported systems in get_adcp_capabilities.", "items": { - "type": "string" + "type": "object", + "properties": { + "system": { + "$ref": "/schemas/enums/postal-system.json", + "description": "Postal code system (e.g., 'us_zip', 'gb_outward'). System name encodes country and precision." + }, + "values": { + "type": "array", + "description": "Postal codes within the system (e.g., ['10001', '10002'] for us_zip)", + "items": { + "type": "string" + }, + "minItems": 1 + } + }, + "required": ["system", "values"], + "additionalProperties": false } }, "axe_include_segment": { diff --git a/static/schemas/source/enums/geo-level.json b/static/schemas/source/enums/geo-level.json new file mode 100644 index 0000000000..32864a99c4 --- /dev/null +++ b/static/schemas/source/enums/geo-level.json @@ -0,0 +1,13 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/enums/geo-level.json", + "title": "Geographic Targeting Level", + "description": "Geographic targeting granularity levels. Some levels (metro, postal_area) require a system specification.", + "type": "string", + "enum": [ + "country", + "region", + "metro", + "postal_area" + ] +} diff --git a/static/schemas/source/enums/metro-system.json b/static/schemas/source/enums/metro-system.json new file mode 100644 index 0000000000..3494ff8442 --- /dev/null +++ b/static/schemas/source/enums/metro-system.json @@ -0,0 +1,14 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/enums/metro-system.json", + "title": "Metro Area System", + "description": "Metro area classification systems for geographic targeting", + "type": "string", + "enum": [ + "nielsen_dma", + "uk_itl1", + "uk_itl2", + "eurostat_nuts2", + "custom" + ] +} diff --git a/static/schemas/source/enums/postal-system.json b/static/schemas/source/enums/postal-system.json new file mode 100644 index 0000000000..ae3b08f66b --- /dev/null +++ b/static/schemas/source/enums/postal-system.json @@ -0,0 +1,18 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/enums/postal-system.json", + "title": "Postal Code System", + "description": "Postal code systems for geographic targeting. System names encode country and precision level.", + "type": "string", + "enum": [ + "us_zip", + "us_zip_plus_four", + "gb_outward", + "gb_full", + "ca_fsa", + "ca_full", + "de_plz", + "fr_code_postal", + "au_postcode" + ] +} diff --git a/static/schemas/source/index.json b/static/schemas/source/index.json index 2cb6ed00ca..56c7eb4c41 100644 --- a/static/schemas/source/index.json +++ b/static/schemas/source/index.json @@ -31,7 +31,7 @@ ] } }, - "lastUpdated": "2025-11-22", + "lastUpdated": "2025-01-23", "baseUrl": "/schemas/v1", "schemas": { "core": { @@ -361,6 +361,18 @@ "creative-sort-field": { "$ref": "/schemas/enums/creative-sort-field.json", "description": "Fields available for sorting creative listings" + }, + "geo-level": { + "$ref": "/schemas/enums/geo-level.json", + "description": "Geographic targeting granularity levels (country, region, metro, postal_area)" + }, + "metro-system": { + "$ref": "/schemas/enums/metro-system.json", + "description": "Metro area classification systems for geographic targeting (nielsen_dma, uk_itl1, uk_itl2, eurostat_nuts2)" + }, + "postal-system": { + "$ref": "/schemas/enums/postal-system.json", + "description": "Postal code systems for geographic targeting. System names encode country and precision (us_zip, gb_outward, ca_fsa, etc.)" } } }, @@ -489,6 +501,8 @@ } }, "list-authorized-properties": { + "deprecated": true, + "deprecation_note": "Replaced by get_capabilities which provides expanded capability declaration", "request": { "$ref": "/schemas/media-buy/list-authorized-properties-request.json", "description": "Request parameters for discovering all properties this agent is authorized to represent" @@ -623,16 +637,6 @@ } }, "tasks": { - "list-property-features": { - "request": { - "$ref": "/schemas/property/list-property-features-request.json", - "description": "Request parameters for discovering governance agent capabilities" - }, - "response": { - "$ref": "/schemas/property/list-property-features-response.json", - "description": "Response payload for list_property_features task" - } - }, "create-property-list": { "request": { "$ref": "/schemas/property/create-property-list-request.json", @@ -755,6 +759,21 @@ } } }, + "protocol": { + "description": "Protocol-level tasks that work across all AdCP domain protocols", + "tasks": { + "get-adcp-capabilities": { + "request": { + "$ref": "/schemas/protocol/get-adcp-capabilities-request.json", + "description": "Request parameters for cross-protocol capability discovery" + }, + "response": { + "$ref": "/schemas/protocol/get-adcp-capabilities-response.json", + "description": "Response payload for get_adcp_capabilities task - includes AdCP version, supported protocols, and protocol-specific capabilities (media_buy, signals, etc.)" + } + } + } + }, "adagents": { "description": "Authorized sales agents file format specification", "$ref": "/schemas/adagents.json", @@ -766,7 +785,9 @@ "schemas": { "adcp-extension": { "$ref": "/schemas/protocols/adcp-extension.json", - "description": "AdCP extension for agent cards (MCP and A2A). Declares AdCP version, supported protocol domains, and typed extensions." + "deprecated": true, + "deprecation_note": "Use tool-based discovery instead. Check for 'get_adcp_capabilities' tool, then call it for full capability details.", + "description": "DEPRECATED: AdCP extension for agent cards. Use get_adcp_capabilities tool for discovery instead." } } }, diff --git a/static/schemas/source/property/list-property-features-request.json b/static/schemas/source/property/list-property-features-request.json deleted file mode 100644 index 3c16d096c1..0000000000 --- a/static/schemas/source/property/list-property-features-request.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/property/list-property-features-request.json", - "title": "List Property Features Request", - "description": "Request payload for list_property_features task. Discovers what features a governance agent can evaluate.", - "type": "object", - "properties": { - "property_types": { - "type": "array", - "description": "Filter to features available for these property types", - "items": { - "type": "string" - } - }, - "countries": { - "type": "array", - "description": "Filter to features available in these countries", - "items": { - "type": "string" - } - }, - "ext": { - "$ref": "/schemas/core/ext.json" - } - }, - "additionalProperties": false -} diff --git a/static/schemas/source/property/list-property-features-response.json b/static/schemas/source/property/list-property-features-response.json deleted file mode 100644 index efbf849fd4..0000000000 --- a/static/schemas/source/property/list-property-features-response.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/property/list-property-features-response.json", - "title": "List Property Features Response", - "description": "Response payload for list_property_features task. Returns the features this governance agent can evaluate.", - "type": "object", - "properties": { - "features": { - "type": "array", - "description": "Features this agent can evaluate", - "items": { - "$ref": "/schemas/property/property-feature-definition.json" - } - }, - "ext": { - "$ref": "/schemas/core/ext.json" - } - }, - "required": ["features"], - "additionalProperties": false -} diff --git a/static/schemas/source/protocol/get-adcp-capabilities-request.json b/static/schemas/source/protocol/get-adcp-capabilities-request.json new file mode 100644 index 0000000000..7c49d2cd15 --- /dev/null +++ b/static/schemas/source/protocol/get-adcp-capabilities-request.json @@ -0,0 +1,24 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/protocol/get-adcp-capabilities-request.json", + "title": "Get AdCP Capabilities Request", + "description": "Request payload for get_adcp_capabilities task. Protocol-level capability discovery that works across all AdCP protocols.", + "type": "object", + "properties": { + "protocols": { + "type": "array", + "description": "Specific protocols to query capabilities for. If omitted, returns capabilities for all supported protocols.", + "items": { + "type": "string", + "enum": ["media_buy", "signals"] + } + }, + "context": { + "$ref": "/schemas/core/context.json" + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "additionalProperties": true +} diff --git a/static/schemas/source/protocol/get-adcp-capabilities-response.json b/static/schemas/source/protocol/get-adcp-capabilities-response.json new file mode 100644 index 0000000000..e64d9e3aee --- /dev/null +++ b/static/schemas/source/protocol/get-adcp-capabilities-response.json @@ -0,0 +1,323 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/protocol/get-adcp-capabilities-response.json", + "title": "Get AdCP Capabilities Response", + "description": "Response payload for get_adcp_capabilities task. Protocol-level capability discovery across all AdCP protocols. Each domain protocol has its own capability section.", + "type": "object", + "properties": { + "adcp": { + "type": "object", + "description": "Core AdCP protocol information", + "properties": { + "major_versions": { + "type": "array", + "description": "AdCP major versions supported by this seller. Major versions indicate breaking changes.", + "items": { + "type": "integer", + "minimum": 1 + }, + "minItems": 1 + } + }, + "required": ["major_versions"] + }, + "supported_protocols": { + "type": "array", + "description": "Which AdCP domain protocols this seller supports", + "items": { + "type": "string", + "enum": ["media_buy", "signals", "governance"] + }, + "minItems": 1 + }, + "media_buy": { + "type": "object", + "description": "Media-buy protocol capabilities. Only present if media_buy is in supported_protocols.", + "properties": { + "features": { + "type": "object", + "description": "Optional media-buy features supported. If declared true, the seller MUST honor requests using that feature.", + "properties": { + "inline_creative_management": { + "type": "boolean", + "description": "Supports creatives provided inline in create_media_buy requests" + }, + "property_list_filtering": { + "type": "boolean", + "description": "Honors property_list parameter in get_products to filter results to buyer-approved properties" + }, + "content_standards": { + "type": "boolean", + "description": "Full support for content_standards configuration including sampling rates and category filtering" + } + }, + "additionalProperties": { + "type": "boolean" + } + }, + "execution": { + "type": "object", + "description": "Technical execution capabilities for media buying", + "properties": { + "axe_integrations": { + "type": "array", + "description": "Agentic ad exchange (AXE) integrations supported. URLs are canonical identifiers for exchanges this seller can execute through.", + "items": { + "type": "string", + "format": "uri" + } + }, + "creative_specs": { + "type": "object", + "description": "Creative specification support", + "properties": { + "vast_versions": { + "type": "array", + "description": "VAST versions supported for video creatives", + "items": { + "type": "string", + "pattern": "^[0-9]+\\.[0-9]+$" + } + }, + "mraid_versions": { + "type": "array", + "description": "MRAID versions supported for rich media mobile creatives", + "items": { + "type": "string", + "pattern": "^[0-9]+\\.[0-9]+$" + } + }, + "vpaid": { + "type": "boolean", + "description": "VPAID support for interactive video ads" + }, + "simid": { + "type": "boolean", + "description": "SIMID support for interactive video ads" + } + } + }, + "targeting": { + "type": "object", + "description": "Targeting capabilities. If declared true/supported, buyer can use these targeting parameters and seller MUST honor them.", + "properties": { + "geo_countries": { + "type": "boolean", + "description": "Supports country-level geo targeting using ISO 3166-1 alpha-2 codes (e.g., 'US', 'GB', 'DE')" + }, + "geo_regions": { + "type": "boolean", + "description": "Supports region/state-level geo targeting using ISO 3166-2 subdivision codes (e.g., 'US-NY', 'GB-SCT', 'DE-BY')" + }, + "geo_metros": { + "type": "object", + "description": "Metro area targeting support. Specifies which classification systems are supported.", + "properties": { + "nielsen_dma": { + "type": "boolean", + "description": "Supports Nielsen DMA codes (US market, e.g., '501' for NYC)" + }, + "uk_itl1": { + "type": "boolean", + "description": "Supports UK ITL Level 1 regions" + }, + "uk_itl2": { + "type": "boolean", + "description": "Supports UK ITL Level 2 regions" + }, + "eurostat_nuts2": { + "type": "boolean", + "description": "Supports Eurostat NUTS Level 2 regions (EU)" + } + } + }, + "geo_postal_areas": { + "type": "object", + "description": "Postal area targeting support. Specifies which postal code systems are supported. System names encode country and precision.", + "properties": { + "us_zip": { + "type": "boolean", + "description": "US 5-digit ZIP codes (e.g., '10001')" + }, + "us_zip_plus_four": { + "type": "boolean", + "description": "US 9-digit ZIP+4 codes (e.g., '10001-1234')" + }, + "gb_outward": { + "type": "boolean", + "description": "UK postcode district / outward code (e.g., 'SW1', 'EC1')" + }, + "gb_full": { + "type": "boolean", + "description": "UK full postcode (e.g., 'SW1A 1AA')" + }, + "ca_fsa": { + "type": "boolean", + "description": "Canadian Forward Sortation Area (e.g., 'K1A')" + }, + "ca_full": { + "type": "boolean", + "description": "Canadian full postal code (e.g., 'K1A 0B1')" + }, + "de_plz": { + "type": "boolean", + "description": "German Postleitzahl, 5 digits (e.g., '10115')" + }, + "fr_code_postal": { + "type": "boolean", + "description": "French code postal, 5 digits (e.g., '75001')" + }, + "au_postcode": { + "type": "boolean", + "description": "Australian postcode, 4 digits (e.g., '2000')" + } + } + } + } + } + } + }, + "portfolio": { + "type": "object", + "description": "Information about the seller's media inventory portfolio", + "properties": { + "publisher_domains": { + "type": "array", + "description": "Publisher domains this seller is authorized to represent. Buyers should fetch each publisher's adagents.json for property definitions.", + "items": { + "type": "string", + "pattern": "^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$" + }, + "minItems": 1 + }, + "primary_channels": { + "type": "array", + "description": "Primary advertising channels in this portfolio", + "items": { + "$ref": "/schemas/enums/channels.json" + } + }, + "primary_countries": { + "type": "array", + "description": "Primary countries (ISO 3166-1 alpha-2) where inventory is concentrated", + "items": { + "type": "string", + "pattern": "^[A-Z]{2}$" + } + }, + "description": { + "type": "string", + "description": "Markdown-formatted description of the inventory portfolio", + "maxLength": 5000 + }, + "advertising_policies": { + "type": "string", + "description": "Advertising content policies, restrictions, and guidelines", + "maxLength": 10000 + } + }, + "required": ["publisher_domains"] + } + } + }, + "signals": { + "type": "object", + "description": "Signals protocol capabilities. Only present if signals is in supported_protocols. Reserved for future use.", + "properties": { + "features": { + "type": "object", + "description": "Optional signals features supported", + "additionalProperties": { + "type": "boolean" + } + } + } + }, + "governance": { + "type": "object", + "description": "Governance protocol capabilities. Only present if governance is in supported_protocols. Governance agents provide property data like compliance scores, brand safety ratings, and sustainability metrics.", + "properties": { + "property_features": { + "type": "array", + "description": "Property features this governance agent can evaluate. Each feature describes a score, rating, or certification the agent can provide for properties.", + "items": { + "type": "object", + "properties": { + "feature_id": { + "type": "string", + "description": "Unique identifier for this feature (e.g., 'consent_quality', 'coppa_certified', 'carbon_score')" + }, + "type": { + "type": "string", + "enum": ["binary", "quantitative", "categorical"], + "description": "Data type: 'binary' for yes/no, 'quantitative' for numeric scores, 'categorical' for enum values" + }, + "range": { + "type": "object", + "description": "For quantitative features, the valid range", + "properties": { + "min": { + "type": "number", + "description": "Minimum value" + }, + "max": { + "type": "number", + "description": "Maximum value" + } + }, + "required": ["min", "max"] + }, + "categories": { + "type": "array", + "description": "For categorical features, the valid values", + "items": { + "type": "string" + } + }, + "description": { + "type": "string", + "description": "Human-readable description of what this feature measures" + }, + "methodology_url": { + "type": "string", + "format": "uri", + "description": "URL to documentation explaining how this feature is calculated or measured. Helps buyers understand and compare methodologies across vendors." + } + }, + "required": ["feature_id", "type"] + } + } + } + }, + "extensions_supported": { + "type": "array", + "description": "Extension namespaces this agent supports. Buyers can expect meaningful data in ext.{namespace} fields on responses from this agent. Extension schemas are published in the AdCP extension registry.", + "items": { + "type": "string", + "pattern": "^[a-z][a-z0-9_]*$", + "description": "Extension namespace (lowercase alphanumeric with underscores, e.g., 'scope3', 'garm', 'iab_tcf')" + }, + "uniqueItems": true + }, + "last_updated": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 timestamp of when capabilities were last updated. Buyers can use this for cache invalidation." + }, + "errors": { + "type": "array", + "description": "Task-specific errors and warnings", + "items": { + "$ref": "/schemas/core/error.json" + } + }, + "context": { + "$ref": "/schemas/core/context.json" + }, + "ext": { + "$ref": "/schemas/core/ext.json" + } + }, + "required": ["adcp", "supported_protocols"], + "additionalProperties": true +} diff --git a/static/schemas/source/protocols/adcp-extension.json b/static/schemas/source/protocols/adcp-extension.json index 6c27ac7491..ea104fb63c 100644 --- a/static/schemas/source/protocols/adcp-extension.json +++ b/static/schemas/source/protocols/adcp-extension.json @@ -1,14 +1,17 @@ { "$schema": "http://json-schema.org/draft-07/schema#", "$id": "/schemas/protocols/adcp-extension.json", - "title": "AdCP Agent Card Extension Params", - "description": "Parameters for declaring AdCP support in agent discovery. For A2A, use in extensions[].params. For MCP, use in _meta['adcontextprotocol.org'].", + "title": "AdCP Agent Card Extension Params (Deprecated)", + "description": "DEPRECATED: Use tool-based discovery instead. Check for 'get_adcp_capabilities' tool in the agent's tool list, then call it for full capability details. This extension schema is maintained for backward compatibility only.", + "deprecated": true, + "deprecation_note": "AdCP discovery now uses native MCP/A2A tool discovery. If an agent has 'get_adcp_capabilities' tool, it supports AdCP. Call get_adcp_capabilities for version, protocols, features, and capabilities.", "type": "object", "properties": { "adcp_version": { "type": "string", "pattern": "^\\d+\\.\\d+\\.\\d+$", - "description": "Semantic version of the AdCP specification this agent implements (e.g., '2.5.0'). Extension schemas are versioned along with the AdCP spec." + "description": "DEPRECATED: Use get_adcp_capabilities response adcp.major_versions instead.", + "deprecated": true }, "protocols_supported": { "type": "array", @@ -22,17 +25,18 @@ }, "minItems": 1, "uniqueItems": true, - "description": "AdCP protocol domains supported by this agent. At least one must be specified." + "description": "DEPRECATED: Use get_adcp_capabilities response supported_protocols instead.", + "deprecated": true }, "extensions_supported": { "type": "array", - "description": "Typed extensions this agent supports. Each extension has a formal schema in /schemas/extensions/. Extension version is determined by adcp_version.", + "description": "DEPRECATED: Typed extensions can be declared in get_adcp_capabilities ext field.", "items": { "type": "string", - "pattern": "^[a-z][a-z0-9_]*$", - "description": "Extension namespace (e.g., 'sustainability'). Must be lowercase alphanumeric with underscores." + "pattern": "^[a-z][a-z0-9_]*$" }, - "uniqueItems": true + "uniqueItems": true, + "deprecated": true } }, "required": [ From 4c2f1267297e010fbc439acdb32e5cc86fced7fa Mon Sep 17 00:00:00 2001 From: Brian O'Kelley Date: Sat, 24 Jan 2026 11:37:44 -0500 Subject: [PATCH 31/34] chore: overhaul docs versioning for 2.6.x release MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Merge 2.6.x branch into main (Property Governance, Content Standards, etc.) - Create dist/docs/2.5.3/ frozen snapshot of 2.5 documentation - Update docs.json versioning: "2.6" → docs/, "2.5" → dist/docs/2.5.3/ - Add release-docs.yml workflow for future doc snapshots on release - Remove old v2.6-rc sync workflow (no longer needed) - Update .gitignore to allow dist/docs/ - Update pre-push hook to exclude archived docs from link check This establishes a sustainable versioning model where: - docs/ is always the current/latest version - dist/docs/{version}/ contains frozen release snapshots - Maintenance branches can release docs via the release workflow Co-Authored-By: Claude Opus 4.5 --- .github/workflows/release-docs.yml | 144 ++++ .github/workflows/sync-versioned-docs.yml | 110 --- .gitignore | 3 +- .husky/pre-push | 6 +- .../docs => dist/docs/2.5.3}/adcp-flows.png | Bin .../docs => dist/docs/2.5.3}/adcp_flows.png | Bin .../docs/2.5.3}/community/working-group.mdx | 0 .../contributing/testable-examples-demo.md | 0 .../2.5.3}/contributing/testable-snippets.md | 0 .../docs/2.5.3}/creative/asset-types.mdx | 36 +- .../docs/2.5.3}/creative/brand-manifest.mdx | 96 +-- .../docs/2.5.3}/creative/channels/audio.mdx | 0 .../2.5.3}/creative/channels/carousels.mdx | 0 .../docs/2.5.3}/creative/channels/display.mdx | 0 .../docs/2.5.3}/creative/channels/dooh.mdx | 0 .../docs/2.5.3}/creative/channels/video.mdx | 0 .../2.5.3}/creative/creative-manifests.mdx | 0 .../docs/2.5.3}/creative/formats.mdx | 65 +- .../2.5.3}/creative/generative-creative.mdx | 0 .../creative/implementing-creative-agents.mdx | 4 +- .../docs/2.5.3}/creative/index.mdx | 0 .../task-reference/build_creative.mdx | 0 .../task-reference/list_creative_formats.mdx | 5 +- .../preview_creative-advanced.mdx | 0 .../task-reference/preview_creative.mdx | 0 .../2.5.3}/creative/template-format-ids.mdx | 0 .../docs/2.5.3}/creative/universal-macros.mdx | 0 .../docs/2.5.3}/curation/coming-soon.mdx | 0 {v2.6-rc/docs => dist/docs/2.5.3}/intro.mdx | 18 +- .../docs/2.5.3}/layers-of-the-stack.png | Bin .../agentic-execution-engine.mdx | 0 .../media-buy/advanced-topics/index.mdx | 0 .../advanced-topics/orchestrator-design.mdx | 0 .../advanced-topics/pricing-models.mdx | 0 .../principals-and-security.mdx | 0 .../media-buy/advanced-topics/targeting.mdx | 0 .../media-buy/advanced-topics/testing.mdx | 0 .../capability-discovery}/adagents.mdx | 8 +- .../authorized-properties.mdx | 7 +- .../implementing-standard-formats.mdx | 0 .../media-buy/capability-discovery/index.mdx | 6 +- .../docs/2.5.3}/media-buy/creatives/index.mdx | 0 .../docs/2.5.3}/media-buy/index.mdx | 4 +- .../media-buy/media-buying-lifecycle.png | Bin .../2.5.3}/media-buy/media-buys/index.mdx | 0 .../media-buys/optimization-reporting.mdx | 0 .../media-buys/policy-compliance.mdx | 0 .../product-discovery/brief-expectations.mdx | 0 .../product-discovery/example-briefs.mdx | 0 .../media-buy/product-discovery/index.mdx | 0 .../product-discovery/media-products.mdx | 0 .../task-reference/create_media_buy.mdx | 6 +- .../task-reference/get_media_buy_delivery.mdx | 0 .../media-buy/task-reference/get_products.mdx | 81 -- .../2.5.3}/media-buy/task-reference/index.mdx | 0 .../list_authorized_properties.mdx | 2 +- .../task-reference/list_creative_formats.mdx | 0 .../task-reference/list_creatives.mdx | 54 +- .../provide_performance_feedback.mdx | 0 .../task-reference/sync_creatives.mdx | 8 +- .../task-reference/update_media_buy.mdx | 45 +- .../docs/2.5.3}/protocols/a2a-guide.mdx | 39 +- .../2.5.3}/protocols/a2a-response-format.mdx | 0 .../2.5.3}/protocols/context-management.mdx | 4 +- .../docs/2.5.3}/protocols/core-concepts.mdx | 0 .../2.5.3}/protocols/envelope-examples.mdx | 0 .../docs/2.5.3}/protocols/error-handling.mdx | 0 .../docs/2.5.3}/protocols/getting-started.mdx | 0 .../initator-context-lifecycle-01.png | Bin .../initator-context-lifecycle-02.png | Bin .../docs/2.5.3}/protocols/mcp-guide.mdx | 52 +- .../2.5.3}/protocols/protocol-comparison.mdx | 0 .../docs/2.5.3}/protocols/task-management.mdx | 0 .../docs => dist/docs/2.5.3}/quickstart.mdx | 0 .../docs/2.5.3}/reference/ad-tech-primer.mdx | 0 .../docs/2.5.3}/reference/adcp-ecosystem.mdx | 0 .../docs/2.5.3}/reference/authentication.mdx | 0 .../docs/2.5.3}/reference/changelog.mdx | 0 .../reference/creative-quick-reference.mdx | 0 .../docs/2.5.3}/reference/data-models.mdx | 4 +- .../docs/2.5.3}/reference/error-codes.mdx | 60 +- .../reference/extensions-and-context.mdx | 207 ----- .../docs/2.5.3}/reference/glossary.mdx | 16 +- .../docs/2.5.3}/reference/gmsf-reference.mdx | 0 .../docs/2.5.3}/reference/implementor-faq.mdx | 2 +- .../reference/media-buy-quick-reference.mdx | 0 .../docs/2.5.3}/reference/release-notes.mdx | 0 .../docs/2.5.3}/reference/roadmap.mdx | 4 +- .../2.5.3}/reference/schema-versioning.mdx | 28 +- .../docs/2.5.3}/reference/security.mdx | 122 ++- .../reference/signals-quick-reference.mdx | 0 .../docs/2.5.3}/signals/overview.mdx | 0 .../docs/2.5.3}/signals/specification.mdx | 20 +- .../2.5.3}/signals/tasks/activate_signal.mdx | 0 .../docs/2.5.3}/signals/tasks/get_signals.mdx | 0 .../docs/2.5.3}/spec-guidelines.md | 0 docs.json | 216 ++--- scripts/sync-versioned-docs.sh | 55 -- .../docs/governance/brand-standards/index.mdx | 90 --- .../content-standards/artifacts.mdx | 304 ------- .../implementation-guide.mdx | 381 --------- .../governance/content-standards/index.mdx | 358 --------- .../tasks/calibrate_content.mdx | 228 ------ .../tasks/create_content_standards.mdx | 90 --- .../tasks/delete_content_standards.mdx | 70 -- .../tasks/get_content_standards.mdx | 77 -- .../tasks/get_media_buy_artifacts.mdx | 205 ----- .../tasks/list_content_standards.mdx | 67 -- .../tasks/update_content_standards.mdx | 72 -- .../tasks/validate_content_delivery.mdx | 183 ----- v2.6-rc/docs/governance/index.mdx | 187 ----- v2.6-rc/docs/governance/property/index.mdx | 227 ------ .../governance/property/specification.mdx | 611 --------------- .../docs/governance/property/tasks/index.mdx | 153 ---- .../property/tasks/list_property_features.mdx | 235 ------ .../property/tasks/property_lists.mdx | 701 ----------------- .../tasks/validate_property_delivery.mdx | 402 ---------- .../docs/reference/media-channel-taxonomy.mdx | 740 ------------------ 118 files changed, 456 insertions(+), 6462 deletions(-) create mode 100644 .github/workflows/release-docs.yml delete mode 100644 .github/workflows/sync-versioned-docs.yml rename {v2.6-rc/docs => dist/docs/2.5.3}/adcp-flows.png (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/adcp_flows.png (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/community/working-group.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/contributing/testable-examples-demo.md (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/contributing/testable-snippets.md (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/creative/asset-types.mdx (91%) rename {v2.6-rc/docs => dist/docs/2.5.3}/creative/brand-manifest.mdx (78%) rename {v2.6-rc/docs => dist/docs/2.5.3}/creative/channels/audio.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/creative/channels/carousels.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/creative/channels/display.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/creative/channels/dooh.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/creative/channels/video.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/creative/creative-manifests.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/creative/formats.mdx (88%) rename {v2.6-rc/docs => dist/docs/2.5.3}/creative/generative-creative.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/creative/implementing-creative-agents.mdx (97%) rename {v2.6-rc/docs => dist/docs/2.5.3}/creative/index.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/creative/task-reference/build_creative.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/creative/task-reference/list_creative_formats.mdx (98%) rename {v2.6-rc/docs => dist/docs/2.5.3}/creative/task-reference/preview_creative-advanced.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/creative/task-reference/preview_creative.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/creative/template-format-ids.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/creative/universal-macros.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/curation/coming-soon.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/intro.mdx (90%) rename {v2.6-rc/docs => dist/docs/2.5.3}/layers-of-the-stack.png (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/media-buy/advanced-topics/agentic-execution-engine.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/media-buy/advanced-topics/index.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/media-buy/advanced-topics/orchestrator-design.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/media-buy/advanced-topics/pricing-models.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/media-buy/advanced-topics/principals-and-security.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/media-buy/advanced-topics/targeting.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/media-buy/advanced-topics/testing.mdx (100%) rename {v2.6-rc/docs/governance/property => dist/docs/2.5.3/media-buy/capability-discovery}/adagents.mdx (98%) rename {v2.6-rc/docs/governance/property => dist/docs/2.5.3/media-buy/capability-discovery}/authorized-properties.mdx (97%) rename {v2.6-rc/docs => dist/docs/2.5.3}/media-buy/capability-discovery/implementing-standard-formats.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/media-buy/capability-discovery/index.mdx (93%) rename {v2.6-rc/docs => dist/docs/2.5.3}/media-buy/creatives/index.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/media-buy/index.mdx (97%) rename {v2.6-rc/docs => dist/docs/2.5.3}/media-buy/media-buying-lifecycle.png (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/media-buy/media-buys/index.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/media-buy/media-buys/optimization-reporting.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/media-buy/media-buys/policy-compliance.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/media-buy/product-discovery/brief-expectations.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/media-buy/product-discovery/example-briefs.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/media-buy/product-discovery/index.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/media-buy/product-discovery/media-products.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/media-buy/task-reference/create_media_buy.mdx (97%) rename {v2.6-rc/docs => dist/docs/2.5.3}/media-buy/task-reference/get_media_buy_delivery.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/media-buy/task-reference/get_products.mdx (90%) rename {v2.6-rc/docs => dist/docs/2.5.3}/media-buy/task-reference/index.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/media-buy/task-reference/list_authorized_properties.mdx (99%) rename {v2.6-rc/docs => dist/docs/2.5.3}/media-buy/task-reference/list_creative_formats.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/media-buy/task-reference/list_creatives.mdx (92%) rename {v2.6-rc/docs => dist/docs/2.5.3}/media-buy/task-reference/provide_performance_feedback.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/media-buy/task-reference/sync_creatives.mdx (96%) rename {v2.6-rc/docs => dist/docs/2.5.3}/media-buy/task-reference/update_media_buy.mdx (89%) rename {v2.6-rc/docs => dist/docs/2.5.3}/protocols/a2a-guide.mdx (94%) rename {v2.6-rc/docs => dist/docs/2.5.3}/protocols/a2a-response-format.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/protocols/context-management.mdx (92%) rename {v2.6-rc/docs => dist/docs/2.5.3}/protocols/core-concepts.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/protocols/envelope-examples.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/protocols/error-handling.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/protocols/getting-started.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/protocols/initator-context-lifecycle-01.png (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/protocols/initator-context-lifecycle-02.png (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/protocols/mcp-guide.mdx (91%) rename {v2.6-rc/docs => dist/docs/2.5.3}/protocols/protocol-comparison.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/protocols/task-management.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/quickstart.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/reference/ad-tech-primer.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/reference/adcp-ecosystem.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/reference/authentication.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/reference/changelog.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/reference/creative-quick-reference.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/reference/data-models.mdx (99%) rename {v2.6-rc/docs => dist/docs/2.5.3}/reference/error-codes.mdx (89%) rename {v2.6-rc/docs => dist/docs/2.5.3}/reference/extensions-and-context.mdx (56%) rename {v2.6-rc/docs => dist/docs/2.5.3}/reference/glossary.mdx (89%) rename {v2.6-rc/docs => dist/docs/2.5.3}/reference/gmsf-reference.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/reference/implementor-faq.mdx (98%) rename {v2.6-rc/docs => dist/docs/2.5.3}/reference/media-buy-quick-reference.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/reference/release-notes.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/reference/roadmap.mdx (94%) rename {v2.6-rc/docs => dist/docs/2.5.3}/reference/schema-versioning.mdx (93%) rename {v2.6-rc/docs => dist/docs/2.5.3}/reference/security.mdx (89%) rename {v2.6-rc/docs => dist/docs/2.5.3}/reference/signals-quick-reference.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/signals/overview.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/signals/specification.mdx (96%) rename {v2.6-rc/docs => dist/docs/2.5.3}/signals/tasks/activate_signal.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/signals/tasks/get_signals.mdx (100%) rename {v2.6-rc/docs => dist/docs/2.5.3}/spec-guidelines.md (100%) delete mode 100755 scripts/sync-versioned-docs.sh delete mode 100644 v2.6-rc/docs/governance/brand-standards/index.mdx delete mode 100644 v2.6-rc/docs/governance/content-standards/artifacts.mdx delete mode 100644 v2.6-rc/docs/governance/content-standards/implementation-guide.mdx delete mode 100644 v2.6-rc/docs/governance/content-standards/index.mdx delete mode 100644 v2.6-rc/docs/governance/content-standards/tasks/calibrate_content.mdx delete mode 100644 v2.6-rc/docs/governance/content-standards/tasks/create_content_standards.mdx delete mode 100644 v2.6-rc/docs/governance/content-standards/tasks/delete_content_standards.mdx delete mode 100644 v2.6-rc/docs/governance/content-standards/tasks/get_content_standards.mdx delete mode 100644 v2.6-rc/docs/governance/content-standards/tasks/get_media_buy_artifacts.mdx delete mode 100644 v2.6-rc/docs/governance/content-standards/tasks/list_content_standards.mdx delete mode 100644 v2.6-rc/docs/governance/content-standards/tasks/update_content_standards.mdx delete mode 100644 v2.6-rc/docs/governance/content-standards/tasks/validate_content_delivery.mdx delete mode 100644 v2.6-rc/docs/governance/index.mdx delete mode 100644 v2.6-rc/docs/governance/property/index.mdx delete mode 100644 v2.6-rc/docs/governance/property/specification.mdx delete mode 100644 v2.6-rc/docs/governance/property/tasks/index.mdx delete mode 100644 v2.6-rc/docs/governance/property/tasks/list_property_features.mdx delete mode 100644 v2.6-rc/docs/governance/property/tasks/property_lists.mdx delete mode 100644 v2.6-rc/docs/governance/property/tasks/validate_property_delivery.mdx delete mode 100644 v2.6-rc/docs/reference/media-channel-taxonomy.mdx diff --git a/.github/workflows/release-docs.yml b/.github/workflows/release-docs.yml new file mode 100644 index 0000000000..010ba9b71d --- /dev/null +++ b/.github/workflows/release-docs.yml @@ -0,0 +1,144 @@ +name: Release Documentation Snapshot + +on: + release: + types: [published] + workflow_dispatch: + inputs: + version: + description: 'Version to snapshot (e.g., 2.6.0)' + required: true + type: string + +jobs: + snapshot-docs: + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + + steps: + - name: Determine version + id: version + run: | + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + VERSION="${{ inputs.version }}" + else + # Extract version from tag (v2.6.0 -> 2.6.0) + VERSION="${GITHUB_REF_NAME#v}" + fi + echo "version=$VERSION" >> $GITHUB_OUTPUT + + # Extract major.minor for docs.json version label (2.6.0 -> 2.6) + MAJOR_MINOR=$(echo "$VERSION" | cut -d. -f1,2) + echo "major_minor=$MAJOR_MINOR" >> $GITHUB_OUTPUT + + - name: Checkout main branch + uses: actions/checkout@v4 + with: + ref: main + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Fetch release tag + if: github.event_name != 'workflow_dispatch' + run: git fetch origin tag ${{ github.ref_name }} + + - name: Create docs snapshot + run: | + VERSION="${{ steps.version.outputs.version }}" + + # Determine source ref + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + SOURCE_REF="v$VERSION" + else + SOURCE_REF="${{ github.ref_name }}" + fi + + # Create dist/docs directory if it doesn't exist + mkdir -p dist/docs + + # Remove existing version if present (allows re-running) + rm -rf "dist/docs/$VERSION" + + # Extract docs from the release tag + git archive "$SOURCE_REF" -- docs | tar -x -C "dist/docs/$VERSION" --strip-components=1 || { + mkdir -p "dist/docs/$VERSION" + git archive "$SOURCE_REF" -- docs | tar -x + mv docs/* "dist/docs/$VERSION/" + rmdir docs 2>/dev/null || true + } + + echo "Created docs snapshot at dist/docs/$VERSION" + ls -la "dist/docs/$VERSION" | head -10 + + - name: Update docs.json + run: | + VERSION="${{ steps.version.outputs.version }}" + MAJOR_MINOR="${{ steps.version.outputs.major_minor }}" + + # Check if this major.minor version already exists in docs.json + EXISTING=$(jq -r ".navigation.versions[] | select(.version == \"$MAJOR_MINOR\") | .version" docs.json) + + if [ -n "$EXISTING" ]; then + echo "Version $MAJOR_MINOR already exists in docs.json, updating paths to $VERSION" + # Update existing version's paths to point to the new patch version + jq --arg old_pattern "dist/docs/[0-9]+\\.[0-9]+\\.[0-9]+/" \ + --arg new_path "dist/docs/$VERSION/" \ + --arg major_minor "$MAJOR_MINOR" \ + ' + def update_paths: + if type == "array" then + map(update_paths) + elif type == "object" then + if has("pages") then + .pages = (.pages | update_paths) + else + . + end + elif type == "string" then + if test("^dist/docs/[0-9]+\\.[0-9]+\\.[0-9]+/") then + sub("^dist/docs/[0-9]+\\.[0-9]+\\.[0-9]+/"; $new_path) + else + . + end + else + . + end; + + .navigation.versions = [ + .navigation.versions[] | + if .version == $major_minor then + .groups = (.groups | update_paths) + else + . + end + ] + ' docs.json > /tmp/updated-docs.json + mv /tmp/updated-docs.json docs.json + else + echo "Version $MAJOR_MINOR is new, adding to docs.json" + # This is a new major.minor version - would need manual nav structure + # For now, just log a warning + echo "::warning::New major.minor version $MAJOR_MINOR requires manual docs.json navigation setup" + fi + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v7 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: "chore: snapshot docs for v${{ steps.version.outputs.version }}" + title: "chore: snapshot docs for v${{ steps.version.outputs.version }}" + body: | + This PR creates a documentation snapshot for release v${{ steps.version.outputs.version }}. + + **Changes:** + - Added `dist/docs/${{ steps.version.outputs.version }}/` with frozen documentation + - Updated `docs.json` to reference the new snapshot + + Auto-generated by the release-docs workflow. + branch: auto/docs-v${{ steps.version.outputs.version }} + delete-branch: true + add-paths: | + dist/docs/${{ steps.version.outputs.version }}/ + docs.json diff --git a/.github/workflows/sync-versioned-docs.yml b/.github/workflows/sync-versioned-docs.yml deleted file mode 100644 index a641090206..0000000000 --- a/.github/workflows/sync-versioned-docs.yml +++ /dev/null @@ -1,110 +0,0 @@ -name: Sync Versioned Docs and Schemas - -on: - push: - branches: - - main - - 2.6.x - workflow_dispatch: # Allow manual trigger - -jobs: - sync-docs: - runs-on: ubuntu-latest - # Only run if triggered by main branch or manually, or if 2.6.x changes - if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/2.6.x' || github.event_name == 'workflow_dispatch' - - steps: - - name: Checkout main branch - uses: actions/checkout@v4 - with: - ref: main - fetch-depth: 0 - token: ${{ secrets.GITHUB_TOKEN }} - - - name: Fetch 2.6.x branch - run: git fetch origin 2.6.x - - - name: Sync docs from 2.6.x to v2.6-rc - run: | - # Remove existing v2.6-rc/docs to ensure clean sync - rm -rf v2.6-rc/docs - mkdir -p v2.6-rc - - # Extract docs folder from 2.6.x branch - git archive origin/2.6.x -- docs | tar -x -C v2.6-rc/ - - - name: Sync schemas from 2.6.x to dist/schemas/2.6.0 - run: | - # Check if dist/schemas/2.6.0 exists in 2.6.x branch - if git ls-tree -d origin/2.6.x -- dist/schemas/2.6.0 > /dev/null 2>&1; then - # Remove existing 2.6.0 schemas to ensure clean sync - rm -rf dist/schemas/2.6.0 - - # Extract dist/schemas/2.6.0 folder from 2.6.x branch - git archive origin/2.6.x -- dist/schemas/2.6.0 | tar -x - echo "Synced dist/schemas/2.6.0 from 2.6.x branch" - else - echo "dist/schemas/2.6.0 does not exist in 2.6.x branch, skipping" - fi - - - name: Sync navigation from 2.6.x docs.json - run: | - # Extract docs.json from 2.6.x branch - git show origin/2.6.x:docs.json > /tmp/source-docs.json - - # Create jq script to transform navigation - # Takes the first version's groups from 2.6.x (which has the actual content) - # and transforms all paths by prepending "v2.6-rc/" - cat << 'JQSCRIPT' > /tmp/transform.jq - def transform_paths: - if type == "array" then - map(transform_paths) - elif type == "object" then - if has("pages") then - .pages = (.pages | transform_paths) - else - . - end - elif type == "string" then - "v2.6-rc/" + . - else - . - end; - - # $source is from --slurpfile (array), so use $source[0] - ($source[0].navigation.versions[0].groups | transform_paths) as $transformed | - (.navigation.versions | to_entries | map(select(.value.version == "2.6-rc")) | .[0].key) as $idx | - if $idx != null then - .navigation.versions[$idx].groups = $transformed - else - . - end - JQSCRIPT - - # Apply transformation: read source groups from 2.6.x, transform paths, update main's docs.json - jq --slurpfile source /tmp/source-docs.json -f /tmp/transform.jq docs.json > /tmp/updated-docs.json - - # Replace docs.json with updated version - mv /tmp/updated-docs.json docs.json - - echo "Synced navigation from 2.6.x docs.json to v2.6-rc version" - - - name: Create Pull Request - uses: peter-evans/create-pull-request@v7 - with: - token: ${{ secrets.GITHUB_TOKEN }} - commit-message: "chore: sync v2.6-rc docs and schemas from 2.6.x branch" - title: "chore: sync v2.6-rc docs and schemas from 2.6.x branch" - body: | - This PR syncs from the 2.6.x branch: - - Documentation to `v2.6-rc/docs/` - - Schemas to `dist/schemas/2.6.0/` (if available) - - Navigation config from 2.6.x's docs.json to main's v2.6-rc version - - Auto-generated by the sync-versioned-docs workflow. - branch: auto/sync-v2.6-rc - delete-branch: true - add-paths: | - v2.6-rc/ - dist/schemas/2.6.0/ - docs.json diff --git a/.gitignore b/.gitignore index d2569fc260..a0a98316a4 100644 --- a/.gitignore +++ b/.gitignore @@ -5,9 +5,10 @@ server/node_modules # Production /build -# Ignore dist except for released schemas +# Ignore dist except for released schemas and docs /dist/* !/dist/schemas +!/dist/docs /dist/schemas/latest /dist/schemas/v* diff --git a/.husky/pre-push b/.husky/pre-push index b39a618810..1e49d08830 100755 --- a/.husky/pre-push +++ b/.husky/pre-push @@ -8,11 +8,11 @@ npm run verify-version-sync echo "🔍 Validating Mintlify documentation..." # Check for broken internal links -# Temporarily remove v2.6-rc docs which have WIP governance links -rm -rf v2.6-rc +# Temporarily remove archived docs which have version-specific links +rm -rf dist/docs npx --yes mintlify@latest broken-links BROKEN_LINKS_EXIT=$? -git checkout v2.6-rc +git checkout dist/docs 2>/dev/null || true if [ $BROKEN_LINKS_EXIT -ne 0 ]; then echo "❌ Mintlify broken links check failed. Please fix broken links before pushing." exit 1 diff --git a/v2.6-rc/docs/adcp-flows.png b/dist/docs/2.5.3/adcp-flows.png similarity index 100% rename from v2.6-rc/docs/adcp-flows.png rename to dist/docs/2.5.3/adcp-flows.png diff --git a/v2.6-rc/docs/adcp_flows.png b/dist/docs/2.5.3/adcp_flows.png similarity index 100% rename from v2.6-rc/docs/adcp_flows.png rename to dist/docs/2.5.3/adcp_flows.png diff --git a/v2.6-rc/docs/community/working-group.mdx b/dist/docs/2.5.3/community/working-group.mdx similarity index 100% rename from v2.6-rc/docs/community/working-group.mdx rename to dist/docs/2.5.3/community/working-group.mdx diff --git a/v2.6-rc/docs/contributing/testable-examples-demo.md b/dist/docs/2.5.3/contributing/testable-examples-demo.md similarity index 100% rename from v2.6-rc/docs/contributing/testable-examples-demo.md rename to dist/docs/2.5.3/contributing/testable-examples-demo.md diff --git a/v2.6-rc/docs/contributing/testable-snippets.md b/dist/docs/2.5.3/contributing/testable-snippets.md similarity index 100% rename from v2.6-rc/docs/contributing/testable-snippets.md rename to dist/docs/2.5.3/contributing/testable-snippets.md diff --git a/v2.6-rc/docs/creative/asset-types.mdx b/dist/docs/2.5.3/creative/asset-types.mdx similarity index 91% rename from v2.6-rc/docs/creative/asset-types.mdx rename to dist/docs/2.5.3/creative/asset-types.mdx index 927fbedf1f..c3d58aa685 100644 --- a/v2.6-rc/docs/creative/asset-types.mdx +++ b/dist/docs/2.5.3/creative/asset-types.mdx @@ -338,9 +338,7 @@ The keys in the assets object correspond to the `asset_id` values defined in the ## Usage in Creative Formats -Creative formats specify their assets using the `assets` array. Each asset has a `required` boolean: -- **`required: true`** - Asset MUST be provided for a valid creative -- **`required: false`** - Asset is optional, enhances the creative (e.g., companion banners, third-party tracking pixels) +Creative formats specify their required assets using `assets_required` (an array): ```json { @@ -348,38 +346,12 @@ Creative formats specify their assets using the `assets` array. Each asset has a "agent_url": "https://creative.adcontextprotocol.org", "id": "video_15s_hosted" }, - "assets": [ - { - "item_type": "individual", - "asset_id": "video_file", - "asset_type": "video", - "required": true, - "requirements": { - "duration_seconds": 15, - "acceptable_formats": ["mp4"], - "acceptable_codecs": ["h264"], - "acceptable_resolutions": ["1920x1080", "1280x720"], - "max_file_size_mb": 30 - } - }, - { - "item_type": "individual", - "asset_id": "impression_tracker", - "asset_type": "url", - "required": false, - "requirements": { - "format": ["url"], - "description": "Third-party impression tracking pixel URL" - } - } - ], - - // DEPRECATED: Use "assets" above instead. Kept for backward compatibility. "assets_required": [ { "item_type": "individual", "asset_id": "video_file", "asset_type": "video", + "required": true, "requirements": { "duration_seconds": 15, "acceptable_formats": ["mp4"], @@ -392,10 +364,6 @@ Creative formats specify their assets using the `assets` array. Each asset has a } ``` - -**Backward Compatibility**: The `assets_required` field is deprecated but still supported. Existing implementations can continue using `assets_required` for required assets only. New implementations should use `assets` with the `required` boolean for full asset discovery. - - ## Repeatable Asset Groups For formats with asset sequences (like carousels, slideshows, stories), see the [Carousel & Multi-Asset Formats guide](/docs/creative/channels/carousels) for complete documentation on repeatable asset group patterns. diff --git a/v2.6-rc/docs/creative/brand-manifest.mdx b/dist/docs/2.5.3/creative/brand-manifest.mdx similarity index 78% rename from v2.6-rc/docs/creative/brand-manifest.mdx rename to dist/docs/2.5.3/creative/brand-manifest.mdx index cb80d8f985..692a6fe993 100644 --- a/v2.6-rc/docs/creative/brand-manifest.mdx +++ b/dist/docs/2.5.3/creative/brand-manifest.mdx @@ -22,7 +22,6 @@ Brand manifests solve a key problem: how to efficiently identify advertisers and ### Key Benefits - **Know Your Customer**: Publishers can verify advertisers meet their standards -- **Privacy Transparency**: Link to privacy policy for consumer consent flows - **Minimal Friction**: Start with just a name or URL, expand as needed - **Cacheable**: Same brand manifest reused across all requests - **Standardized**: Consistent format across all AdCP implementations @@ -244,7 +243,6 @@ The structure of the brand manifest object itself (whether provided inline or ho | Field | Type | Description | |-------|------|-------------| | `name` | string | Brand or business name | -| `privacy_policy_url` | string (uri) | URL to the brand's privacy policy for consumer consent flows | | `logos` | Logo[] | Brand logo assets with semantic tags | | `colors` | Colors | Brand color palette (hex format) | | `fonts` | Fonts | Brand typography guidelines | @@ -327,21 +325,10 @@ The structure of the brand manifest object itself (whether provided inline or ho ```typescript { feed_url: string; // URL to product catalog feed - feed_format?: string; // Format: "google_merchant_center" | "facebook_catalog" | "openai_product_feed" | "custom" + feed_format?: string; // Format of the product feed (default: "google_merchant_center") categories?: string[]; // Product categories available in the catalog last_updated?: string; // When the product catalog was last updated (ISO 8601) update_frequency?: string; // How frequently the catalog is updated - agentic_checkout?: AgenticCheckout; // Optional checkout endpoint configuration -} -``` - -### AgenticCheckout Object - -```typescript -{ - endpoint: string; // Base URL for checkout session API - spec: string; // Checkout API specification (e.g., "openai_agentic_checkout_v1") - supported_payment_providers?: string[]; // Payment providers (e.g., ["stripe", "adyen"]) } ``` @@ -472,7 +459,7 @@ Large retailers should provide product feeds: } ``` -**Supported Feed Formats**: Google Merchant Center, Facebook Catalog, [OpenAI Product Feed](https://developers.openai.com/commerce/specs/feed), Custom +**Supported Feed Formats**: RSS, JSON Feed, Product CSV ### 5. Asset Libraries for Enterprise @@ -505,85 +492,6 @@ Enterprise brands with large asset libraries should provide explicit assets: } ``` -## Privacy Integration - -Brand manifests support privacy transparency through the `privacy_policy_url` field. This enables AI platforms to present explicit privacy choices to users before sharing personal data with advertisers. - -### Consumer Consent Flow - -When an AI assistant helps a user engage with an advertiser (booking a flight, making a purchase, etc.), the platform can use the brand manifest's privacy policy URL to: - -1. **Present explicit consent**: "May I share your details with Delta? [View their privacy policy]" -2. **Enable informed decisions**: Users can review data practices before data handoff -3. **Support machine-readable terms**: Works alongside [MyTerms/IEEE P7012](https://myterms.info) for automated privacy negotiation - -### Example with Privacy Policy - -```json -{ - "$schema": "https://adcontextprotocol.org/schemas/v2/core/brand-manifest.json", - "name": "Delta Airlines", - "url": "https://delta.com", - "privacy_policy_url": "https://delta.com/privacy" -} -``` - -### MyTerms Discovery - -For advertisers implementing [IEEE P7012 (MyTerms)](https://myterms.info), AI platforms can discover machine-readable privacy terms from the advertiser's domain (e.g., `/.well-known/myterms`). The brand manifest's `privacy_policy_url` serves as the human-readable fallback and explicit consent path. - -## Agentic Commerce Integration - -Brand manifests support integration with AI commerce platforms through the `product_catalog` field. This enables AI agents to discover products and complete purchases on behalf of users. - -### OpenAI Commerce - -For merchants implementing [OpenAI's Commerce specifications](https://developers.openai.com/commerce), the brand manifest provides a bridge: - -```json -{ - "$schema": "https://adcontextprotocol.org/schemas/v2/core/brand-manifest.json", - "name": "Shop Example", - "url": "https://shopexample.com", - "privacy_policy_url": "https://shopexample.com/privacy", - "product_catalog": { - "feed_url": "https://shopexample.com/products.jsonl.gz", - "feed_format": "openai_product_feed", - "update_frequency": "daily", - "agentic_checkout": { - "endpoint": "https://api.shopexample.com/checkout_sessions", - "spec": "openai_agentic_checkout_v1", - "supported_payment_providers": ["stripe", "adyen"] - } - } -} -``` - -**Key fields for OpenAI Commerce:** - -| Field | Description | -|-------|-------------| -| `feed_format: "openai_product_feed"` | Indicates the feed conforms to [OpenAI's Product Feed spec](https://developers.openai.com/commerce/specs/feed) | -| `agentic_checkout.endpoint` | Base URL for [OpenAI's Agentic Checkout API](https://developers.openai.com/commerce/specs/checkout) | -| `agentic_checkout.spec` | Version identifier for the checkout spec | - -### Feed Format Mapping - -If you have an existing Google Merchant Center feed, here's how key fields map to OpenAI's spec: - -| OpenAI Field | Google Merchant Center | Notes | -|--------------|----------------------|-------| -| `item_id` | `id` | Direct mapping | -| `title` | `title` | Direct mapping | -| `description` | `description` | Direct mapping | -| `url` | `link` | Direct mapping | -| `brand` | `brand` | Direct mapping | -| `price` | `price` | OpenAI uses number + currency code | -| `availability` | `availability` | Same enum values | -| `image_url` | `image_link` | Direct mapping | -| `is_eligible_search` | N/A | OpenAI-specific flag | -| `is_eligible_checkout` | N/A | OpenAI-specific flag | - ## Evolution and Versioning Brand cards are versioned using the `metadata.version` field: diff --git a/v2.6-rc/docs/creative/channels/audio.mdx b/dist/docs/2.5.3/creative/channels/audio.mdx similarity index 100% rename from v2.6-rc/docs/creative/channels/audio.mdx rename to dist/docs/2.5.3/creative/channels/audio.mdx diff --git a/v2.6-rc/docs/creative/channels/carousels.mdx b/dist/docs/2.5.3/creative/channels/carousels.mdx similarity index 100% rename from v2.6-rc/docs/creative/channels/carousels.mdx rename to dist/docs/2.5.3/creative/channels/carousels.mdx diff --git a/v2.6-rc/docs/creative/channels/display.mdx b/dist/docs/2.5.3/creative/channels/display.mdx similarity index 100% rename from v2.6-rc/docs/creative/channels/display.mdx rename to dist/docs/2.5.3/creative/channels/display.mdx diff --git a/v2.6-rc/docs/creative/channels/dooh.mdx b/dist/docs/2.5.3/creative/channels/dooh.mdx similarity index 100% rename from v2.6-rc/docs/creative/channels/dooh.mdx rename to dist/docs/2.5.3/creative/channels/dooh.mdx diff --git a/v2.6-rc/docs/creative/channels/video.mdx b/dist/docs/2.5.3/creative/channels/video.mdx similarity index 100% rename from v2.6-rc/docs/creative/channels/video.mdx rename to dist/docs/2.5.3/creative/channels/video.mdx diff --git a/v2.6-rc/docs/creative/creative-manifests.mdx b/dist/docs/2.5.3/creative/creative-manifests.mdx similarity index 100% rename from v2.6-rc/docs/creative/creative-manifests.mdx rename to dist/docs/2.5.3/creative/creative-manifests.mdx diff --git a/v2.6-rc/docs/creative/formats.mdx b/dist/docs/2.5.3/creative/formats.mdx similarity index 88% rename from v2.6-rc/docs/creative/formats.mdx rename to dist/docs/2.5.3/creative/formats.mdx index ba6b100d4f..54ae1f1c23 100644 --- a/v2.6-rc/docs/creative/formats.mdx +++ b/dist/docs/2.5.3/creative/formats.mdx @@ -222,60 +222,13 @@ Formats are JSON objects with the following key fields: }, "name": "30-Second Hosted Video", "type": "video", - "assets": [ - { - "item_type": "individual", - "asset_id": "video_file", - "asset_type": "video", - "asset_role": "hero_video", - "required": true, - "requirements": { - "duration": "30s", - "format": ["MP4"], - "resolution": ["1920x1080", "1280x720"] - } - }, - { - "item_type": "individual", - "asset_id": "end_card_image", - "asset_type": "image", - "asset_role": "end_card", - "required": false, - "requirements": { - "dimensions": "1920x1080", - "format": ["PNG", "JPG"] - } - }, - { - "item_type": "individual", - "asset_id": "companion_banner", - "asset_type": "image", - "asset_role": "companion", - "required": false, - "requirements": { - "dimensions": "300x250", - "format": ["PNG", "JPG", "GIF"] - } - }, - { - "item_type": "individual", - "asset_id": "impression_tracker", - "asset_type": "url", - "asset_role": "third_party_tracking", - "required": false, - "requirements": { - "description": "Third-party impression tracking pixel URL" - } - } - ], - - // DEPRECATED: Use "assets" above instead. Kept for backward compatibility. "assets_required": [ { "item_type": "individual", "asset_id": "video_file", "asset_type": "video", "asset_role": "hero_video", + "required": true, "requirements": { "duration": "30s", "format": ["MP4"], @@ -290,24 +243,10 @@ Formats are JSON objects with the following key fields: - **format_id**: Unique identifier (may be namespaced with `domain:id`) - **agent_url**: The creative agent authoritative for this format - **type**: Category (video, display, audio, native, dooh, rich_media) -- **assets**: Array of all asset specifications with `required` boolean indicating mandatory vs optional -- **assets_required**: *(Deprecated)* Array of required asset specifications - use `assets` instead +- **assets_required**: Array of asset specifications - **asset_role**: Identifies asset purpose (hero_image, logo, cta_button, etc.) - **renders**: Array of rendered outputs with dimensions - see below -### Asset Discovery - -The `assets` array enables comprehensive asset discovery. Each asset has a `required` boolean: - -- **`required: true`** - Asset MUST be provided for a valid creative -- **`required: false`** - Asset is optional, enhances the creative when provided (e.g., companion banners, third-party tracking pixels) - -This unified approach helps creative tools and AI agents understand the full capabilities of a format, enabling richer creative experiences when optional assets are available while clearly indicating minimum requirements. - - -**Backward Compatibility**: The `assets_required` field is deprecated but still supported. Existing implementations can continue using `assets_required` for required assets only. New implementations should use `assets` with the `required` boolean on each asset for full asset discovery. - - ### Rendered Outputs and Dimensions Formats specify their rendered outputs via the `renders` array. Most formats produce a single render, but some (companion ads, adaptive formats, multi-placement) produce multiple renders: diff --git a/v2.6-rc/docs/creative/generative-creative.mdx b/dist/docs/2.5.3/creative/generative-creative.mdx similarity index 100% rename from v2.6-rc/docs/creative/generative-creative.mdx rename to dist/docs/2.5.3/creative/generative-creative.mdx diff --git a/v2.6-rc/docs/creative/implementing-creative-agents.mdx b/dist/docs/2.5.3/creative/implementing-creative-agents.mdx similarity index 97% rename from v2.6-rc/docs/creative/implementing-creative-agents.mdx rename to dist/docs/2.5.3/creative/implementing-creative-agents.mdx index abb86bb5d0..98671f1eb2 100644 --- a/v2.6-rc/docs/creative/implementing-creative-agents.mdx +++ b/dist/docs/2.5.3/creative/implementing-creative-agents.mdx @@ -100,7 +100,7 @@ Creative agents must implement these two tasks: Return all formats your agent defines. This is how buyers discover what creative formats you support. **Key responsibilities:** -- Return complete format definitions with all `assets` (both required and optional) +- Return complete format definitions with all `assets_required` - Include your `agent_url` in each format - Use proper namespacing for `format_id` values @@ -169,7 +169,7 @@ When validating manifests: When updating format definitions: -- **Additive changes** (new optional assets with `required: false` in `assets`) are safe +- **Additive changes** (new optional assets) are safe - **Breaking changes** (removing assets, changing requirements) require new format_id - Consider versioning: `youragency.com:format_name_v2` - Maintain backward compatibility when possible diff --git a/v2.6-rc/docs/creative/index.mdx b/dist/docs/2.5.3/creative/index.mdx similarity index 100% rename from v2.6-rc/docs/creative/index.mdx rename to dist/docs/2.5.3/creative/index.mdx diff --git a/v2.6-rc/docs/creative/task-reference/build_creative.mdx b/dist/docs/2.5.3/creative/task-reference/build_creative.mdx similarity index 100% rename from v2.6-rc/docs/creative/task-reference/build_creative.mdx rename to dist/docs/2.5.3/creative/task-reference/build_creative.mdx diff --git a/v2.6-rc/docs/creative/task-reference/list_creative_formats.mdx b/dist/docs/2.5.3/creative/task-reference/list_creative_formats.mdx similarity index 98% rename from v2.6-rc/docs/creative/task-reference/list_creative_formats.mdx rename to dist/docs/2.5.3/creative/task-reference/list_creative_formats.mdx index af0348f718..648c6f6792 100644 --- a/v2.6-rc/docs/creative/task-reference/list_creative_formats.mdx +++ b/dist/docs/2.5.3/creative/task-reference/list_creative_formats.mdx @@ -56,7 +56,7 @@ Formats may produce multiple rendered pieces (e.g., video + companion banner). D | Field | Description | |-------|-------------| -| `formats` | Array of full format definitions (format_id, name, type, requirements, assets, assets_required, renders) | +| `formats` | Array of full format definitions (format_id, name, type, requirements, assets_required, renders) | | `creative_agents` | Optional array of other creative agents providing additional formats | See [Format schema](https://adcontextprotocol.org/schemas/v2/core/format.json) for complete format object structure. @@ -421,8 +421,7 @@ Each format includes: | `name` | Human-readable format name | | `type` | Format type (audio, video, display, dooh) | | `requirements` | Technical requirements (duration, file types, bitrate, etc.) | -| `assets` | Array of all assets with `required` boolean indicating mandatory vs optional | -| `assets_required` | *(Deprecated)* Array of required assets - use `assets` instead | +| `assets_required` | Array of required assets with specifications | | `renders` | Array of rendered output pieces (dimensions, role) | ### Asset Roles diff --git a/v2.6-rc/docs/creative/task-reference/preview_creative-advanced.mdx b/dist/docs/2.5.3/creative/task-reference/preview_creative-advanced.mdx similarity index 100% rename from v2.6-rc/docs/creative/task-reference/preview_creative-advanced.mdx rename to dist/docs/2.5.3/creative/task-reference/preview_creative-advanced.mdx diff --git a/v2.6-rc/docs/creative/task-reference/preview_creative.mdx b/dist/docs/2.5.3/creative/task-reference/preview_creative.mdx similarity index 100% rename from v2.6-rc/docs/creative/task-reference/preview_creative.mdx rename to dist/docs/2.5.3/creative/task-reference/preview_creative.mdx diff --git a/v2.6-rc/docs/creative/template-format-ids.mdx b/dist/docs/2.5.3/creative/template-format-ids.mdx similarity index 100% rename from v2.6-rc/docs/creative/template-format-ids.mdx rename to dist/docs/2.5.3/creative/template-format-ids.mdx diff --git a/v2.6-rc/docs/creative/universal-macros.mdx b/dist/docs/2.5.3/creative/universal-macros.mdx similarity index 100% rename from v2.6-rc/docs/creative/universal-macros.mdx rename to dist/docs/2.5.3/creative/universal-macros.mdx diff --git a/v2.6-rc/docs/curation/coming-soon.mdx b/dist/docs/2.5.3/curation/coming-soon.mdx similarity index 100% rename from v2.6-rc/docs/curation/coming-soon.mdx rename to dist/docs/2.5.3/curation/coming-soon.mdx diff --git a/v2.6-rc/docs/intro.mdx b/dist/docs/2.5.3/intro.mdx similarity index 90% rename from v2.6-rc/docs/intro.mdx rename to dist/docs/2.5.3/intro.mdx index a2c45f6fa3..5ee923163e 100644 --- a/v2.6-rc/docs/intro.mdx +++ b/dist/docs/2.5.3/intro.mdx @@ -7,9 +7,9 @@ keywords: [advertising automation protocol, programmatic advertising API, MCP ad -**🎉 AdCP v2.6.0 Released** +**🎉 AdCP v2.5.0 Released** -Asset discovery release featuring unified `assets` field in format schema for discovering both required and optional assets. Buyers and AI agents can now see ALL assets a format supports. [See what's new →](/docs/reference/release-notes) +Developer experience and API refinement release featuring type safety improvements, batch creative previews (5-10x faster), schema versioning (`/schemas/v2.5/`), template formats with dynamic sizing, enhanced product filtering, and inline creative updates. [See what's new →](/docs/reference/release-notes) Welcome to the Ad Context Protocol (AdCP) documentation—the open standard for agentic advertising. @@ -40,7 +40,7 @@ All tasks and data models are defined with JSON schemas for validation and clien AdCP operates at multiple layers, providing a clean separation between the business roles, orchestration layer, and technical execution: -![Layers of the Stack](./layers-of-the-stack.png) +Layers of the AdCP Stack showing Business Principals, Orchestration, and Technical Execution layers ## The AdCP Ecosystem Layers @@ -75,7 +75,7 @@ Platforms that evaluate sellers and audiences, and execute buying strategies: MCP servers that provide: - **Signal Discovery**: Finding relevant signals (audiences, contextual, geographical, temporal) using natural language - **Signal Activation**: Pushing signals to decisioning platforms -- **Integration**: Connects signal platforms to orchestration via MCP +- **Integration**: Exposes data provider capabilities via MCP #### Sales Agent (Right, Bottom) MCP servers that provide: @@ -105,7 +105,7 @@ The technical infrastructure that: The AdCP ecosystem extends beyond media transactions to include creative production and delivery. This expanded view shows how creative agents integrate with the core AdCP components: -![AdCP Flows with Creative Agents](./adcp_flows.png) +AdCP ecosystem diagram showing Creative, Business, and Technical flows with agent integration ### Three Interconnected Flows @@ -142,8 +142,8 @@ The creative flow operates in parallel with the business and technical flows, en Each AdCP protocol operates within this ecosystem: ### 🎯 Signals Activation Protocol -- **Scope**: Works with **signal platforms** to discover and activate signals directly on **decisioning platforms** -- **Integration**: Direct integration between signal agents and decisioning platforms (DSPs, injective platforms) +- **Scope**: Works with **signal agents** to discover and activate signals directly on **decisioning platforms** +- **Integration**: Direct integration between signal agents and decisioning platforms (DSPs, SSPs, ad servers) - **Workflow**: Find signals → Direct activation on target platform → Ready for campaign use ### 📍 Curation Protocol (Coming Soon) @@ -152,7 +152,7 @@ Each AdCP protocol operates within this ecosystem: - **Workflow**: Define requirements → Find inventory → Package with signals ### 💰 Media Buy Protocol -- **Scope**: Works primarily with **decisioning platforms** (DSPs, injective platforms) +- **Scope**: Works primarily with **decisioning platforms** (DSPs, SSPs, ad servers) - **Integration**: Executes campaigns using curated inventory and activated signals - **Workflow**: Set objectives → Execute buys → Optimize performance @@ -240,7 +240,7 @@ Generate and optimize creative assets using AI-powered agents. AI is buying ads. Make sure it can buy yours. -If you operate a signal platform, DSP, or ad tech solution, AdCP lets AI agents discover and purchase your inventory. [Review the Protocol Specifications](/docs/signals/specification) to get started. +If you operate a data platform, DSP, or ad tech solution, AdCP lets AI agents discover and purchase your inventory. [Review the Protocol Specifications](/docs/signals/specification) to get started. ## For Advertisers & Agencies diff --git a/v2.6-rc/docs/layers-of-the-stack.png b/dist/docs/2.5.3/layers-of-the-stack.png similarity index 100% rename from v2.6-rc/docs/layers-of-the-stack.png rename to dist/docs/2.5.3/layers-of-the-stack.png diff --git a/v2.6-rc/docs/media-buy/advanced-topics/agentic-execution-engine.mdx b/dist/docs/2.5.3/media-buy/advanced-topics/agentic-execution-engine.mdx similarity index 100% rename from v2.6-rc/docs/media-buy/advanced-topics/agentic-execution-engine.mdx rename to dist/docs/2.5.3/media-buy/advanced-topics/agentic-execution-engine.mdx diff --git a/v2.6-rc/docs/media-buy/advanced-topics/index.mdx b/dist/docs/2.5.3/media-buy/advanced-topics/index.mdx similarity index 100% rename from v2.6-rc/docs/media-buy/advanced-topics/index.mdx rename to dist/docs/2.5.3/media-buy/advanced-topics/index.mdx diff --git a/v2.6-rc/docs/media-buy/advanced-topics/orchestrator-design.mdx b/dist/docs/2.5.3/media-buy/advanced-topics/orchestrator-design.mdx similarity index 100% rename from v2.6-rc/docs/media-buy/advanced-topics/orchestrator-design.mdx rename to dist/docs/2.5.3/media-buy/advanced-topics/orchestrator-design.mdx diff --git a/v2.6-rc/docs/media-buy/advanced-topics/pricing-models.mdx b/dist/docs/2.5.3/media-buy/advanced-topics/pricing-models.mdx similarity index 100% rename from v2.6-rc/docs/media-buy/advanced-topics/pricing-models.mdx rename to dist/docs/2.5.3/media-buy/advanced-topics/pricing-models.mdx diff --git a/v2.6-rc/docs/media-buy/advanced-topics/principals-and-security.mdx b/dist/docs/2.5.3/media-buy/advanced-topics/principals-and-security.mdx similarity index 100% rename from v2.6-rc/docs/media-buy/advanced-topics/principals-and-security.mdx rename to dist/docs/2.5.3/media-buy/advanced-topics/principals-and-security.mdx diff --git a/v2.6-rc/docs/media-buy/advanced-topics/targeting.mdx b/dist/docs/2.5.3/media-buy/advanced-topics/targeting.mdx similarity index 100% rename from v2.6-rc/docs/media-buy/advanced-topics/targeting.mdx rename to dist/docs/2.5.3/media-buy/advanced-topics/targeting.mdx diff --git a/v2.6-rc/docs/media-buy/advanced-topics/testing.mdx b/dist/docs/2.5.3/media-buy/advanced-topics/testing.mdx similarity index 100% rename from v2.6-rc/docs/media-buy/advanced-topics/testing.mdx rename to dist/docs/2.5.3/media-buy/advanced-topics/testing.mdx diff --git a/v2.6-rc/docs/governance/property/adagents.mdx b/dist/docs/2.5.3/media-buy/capability-discovery/adagents.mdx similarity index 98% rename from v2.6-rc/docs/governance/property/adagents.mdx rename to dist/docs/2.5.3/media-buy/capability-discovery/adagents.mdx index 9fc17890a8..442dee1805 100644 --- a/v2.6-rc/docs/governance/property/adagents.mdx +++ b/dist/docs/2.5.3/media-buy/capability-discovery/adagents.mdx @@ -1,9 +1,9 @@ --- -sidebar_position: 3 +sidebar_position: 8 title: adagents.json Tech Spec --- -The `adagents.json` file provides a standardized way for publishers to declare their properties and authorize sales agents. This is the foundation of Property Governance - it defines what properties exist and who can sell them. +The `adagents.json` file provides a standardized way for publishers to declare which sales agents are authorized to sell their advertising inventory. This specification addresses authorization transparency and helps prevent unauthorized reselling of publisher inventory. **[AdAgents.json Builder](https://adcontextprotocol.org/adagents)** - Validate existing files or create new ones with guided validation @@ -65,7 +65,6 @@ The file must be valid JSON with UTF-8 encoding and return HTTP 200 status. - **`domain`** *(optional)*: Primary domain of managing entity - **`seller_id`** *(optional)*: Seller ID from IAB Tech Lab sellers.json - **`tag_id`** *(optional)*: TAG Certified Against Fraud ID - - **`privacy_policy_url`** *(optional)*: URL to entity's privacy policy for consumer consent flows **`properties`** *(optional)*: Array of properties covered by this file (canonical property definitions) @@ -358,8 +357,7 @@ Large network using tags for grouping efficiency: "email": "adops@meta.com", "domain": "meta.com", "seller_id": "pub-meta-12345", - "tag_id": "12345", - "privacy_policy_url": "https://www.meta.com/privacy/policy" + "tag_id": "12345" }, "properties": [ { diff --git a/v2.6-rc/docs/governance/property/authorized-properties.mdx b/dist/docs/2.5.3/media-buy/capability-discovery/authorized-properties.mdx similarity index 97% rename from v2.6-rc/docs/governance/property/authorized-properties.mdx rename to dist/docs/2.5.3/media-buy/capability-discovery/authorized-properties.mdx index 37981ec9e5..11d72b671c 100644 --- a/v2.6-rc/docs/governance/property/authorized-properties.mdx +++ b/dist/docs/2.5.3/media-buy/capability-discovery/authorized-properties.mdx @@ -1,6 +1,5 @@ --- -sidebar_position: 2.5 -title: Understanding Authorization +title: Authorized Properties description: Understanding property authorization in AdCP - preventing unauthorized resale and validating sales agent relationships keywords: [authorized properties, adagents.json, unauthorized resale, ads.txt, sales agent authorization, property validation] --- @@ -269,11 +268,11 @@ For complete technical details on implementing the `adagents.json` file format, - Validation code examples and error handling - Security considerations and best practices -See the **[adagents.json Tech Spec](/docs/governance/property/adagents)** for complete implementation guidance. +See the **[adagents.json Tech Spec](/docs/media-buy/capability-discovery/adagents)** for complete implementation guidance. ## Related Documentation - **[`list_authorized_properties`](/docs/media-buy/task-reference/list_authorized_properties)** - API reference for property discovery - **[Product Discovery](/docs/media-buy/product-discovery/)** - How authorization integrates with product discovery - **[Properties Schema](https://adcontextprotocol.org/schemas/v2/core/property.json)** - Technical property data model -- **[adagents.json Tech Spec](/docs/governance/property/adagents)** - Complete `adagents.json` implementation guide \ No newline at end of file +- **[adagents.json Tech Spec](/docs/media-buy/capability-discovery/adagents)** - Complete `adagents.json` implementation guide \ No newline at end of file diff --git a/v2.6-rc/docs/media-buy/capability-discovery/implementing-standard-formats.mdx b/dist/docs/2.5.3/media-buy/capability-discovery/implementing-standard-formats.mdx similarity index 100% rename from v2.6-rc/docs/media-buy/capability-discovery/implementing-standard-formats.mdx rename to dist/docs/2.5.3/media-buy/capability-discovery/implementing-standard-formats.mdx diff --git a/v2.6-rc/docs/media-buy/capability-discovery/index.mdx b/dist/docs/2.5.3/media-buy/capability-discovery/index.mdx similarity index 93% rename from v2.6-rc/docs/media-buy/capability-discovery/index.mdx rename to dist/docs/2.5.3/media-buy/capability-discovery/index.mdx index 297984b4c1..885a0e16c9 100644 --- a/v2.6-rc/docs/media-buy/capability-discovery/index.mdx +++ b/dist/docs/2.5.3/media-buy/capability-discovery/index.mdx @@ -21,7 +21,7 @@ Learn how sales agents can support standard creative formats through the referen - Leverage the Standard Creative Agent for standard formats - Work with publisher-specific creative agents for custom formats -### [Understanding Authorization](/docs/governance/property/authorized-properties) 🔐 +### [Authorized Properties](/docs/media-buy/capability-discovery/authorized-properties) 🔐 Learn how AdCP prevents unauthorized resale and ensures sales agents are legitimate. Understand: - The problem of unauthorized resale in digital advertising @@ -30,7 +30,7 @@ Learn how AdCP prevents unauthorized resale and ensures sales agents are legitim - Property tags and large-scale authorization management -**Cross-Protocol Foundation**: The `adagents.json` authorization system applies across ALL AdCP protocols (Media Buy, Signals, and future Curation). See the [adagents.json specification](/docs/governance/property/adagents) for complete implementation details. +**Cross-Protocol Foundation**: The `adagents.json` authorization system applies across ALL AdCP protocols (Media Buy, Signals, and future Curation). See the [adagents.json specification](/docs/media-buy/capability-discovery/adagents) for complete implementation details. @@ -80,4 +80,4 @@ Together, these capabilities provide the foundation for safe, efficient, and eff - **[Creative Protocol](/docs/creative/)** - Creative agents and manifests - **[Creative Channel Guides](/docs/creative/channels/video)** - Format examples and patterns - **[Creative Manifests](/docs/creative/creative-manifests)** - Understanding creative specifications -- **[adagents.json Specification](/docs/governance/property/adagents)** - Publisher authorization system (applies across all AdCP protocols) \ No newline at end of file +- **[adagents.json Specification](/docs/media-buy/capability-discovery/adagents)** - Publisher authorization system (applies across all AdCP protocols) \ No newline at end of file diff --git a/v2.6-rc/docs/media-buy/creatives/index.mdx b/dist/docs/2.5.3/media-buy/creatives/index.mdx similarity index 100% rename from v2.6-rc/docs/media-buy/creatives/index.mdx rename to dist/docs/2.5.3/media-buy/creatives/index.mdx diff --git a/v2.6-rc/docs/media-buy/index.mdx b/dist/docs/2.5.3/media-buy/index.mdx similarity index 97% rename from v2.6-rc/docs/media-buy/index.mdx rename to dist/docs/2.5.3/media-buy/index.mdx index 5afaa30219..ce1c80cf19 100644 --- a/v2.6-rc/docs/media-buy/index.mdx +++ b/dist/docs/2.5.3/media-buy/index.mdx @@ -195,7 +195,7 @@ This accountability framework transforms the advertising marketplace from a seri The following diagram illustrates the complete lifecycle of a media buy in AdCP: -![Media Buying Lifecycle](./media-buying-lifecycle.png) +Media buying lifecycle diagram showing discovery, creation, delivery, and optimization stages ## Documentation Structure @@ -234,7 +234,7 @@ Choose your path based on your role and needs: 4. **Explore [Optimization & Reporting](/docs/media-buy/media-buys/optimization-reporting)** - Learn performance management ### **For Publishers/Sales Agents** -1. **Learn [Understanding Authorization](/docs/governance/property/authorized-properties)** - Understand authorization requirements +1. **Learn [Authorized Properties](/docs/media-buy/capability-discovery/authorized-properties)** - Understand authorization requirements 2. **Review [Creative Formats](/docs/creative/formats)** - See supported creative specifications 3. **Study [Advanced Topics](/docs/media-buy/advanced-topics/)** - Deep dive into technical implementation diff --git a/v2.6-rc/docs/media-buy/media-buying-lifecycle.png b/dist/docs/2.5.3/media-buy/media-buying-lifecycle.png similarity index 100% rename from v2.6-rc/docs/media-buy/media-buying-lifecycle.png rename to dist/docs/2.5.3/media-buy/media-buying-lifecycle.png diff --git a/v2.6-rc/docs/media-buy/media-buys/index.mdx b/dist/docs/2.5.3/media-buy/media-buys/index.mdx similarity index 100% rename from v2.6-rc/docs/media-buy/media-buys/index.mdx rename to dist/docs/2.5.3/media-buy/media-buys/index.mdx diff --git a/v2.6-rc/docs/media-buy/media-buys/optimization-reporting.mdx b/dist/docs/2.5.3/media-buy/media-buys/optimization-reporting.mdx similarity index 100% rename from v2.6-rc/docs/media-buy/media-buys/optimization-reporting.mdx rename to dist/docs/2.5.3/media-buy/media-buys/optimization-reporting.mdx diff --git a/v2.6-rc/docs/media-buy/media-buys/policy-compliance.mdx b/dist/docs/2.5.3/media-buy/media-buys/policy-compliance.mdx similarity index 100% rename from v2.6-rc/docs/media-buy/media-buys/policy-compliance.mdx rename to dist/docs/2.5.3/media-buy/media-buys/policy-compliance.mdx diff --git a/v2.6-rc/docs/media-buy/product-discovery/brief-expectations.mdx b/dist/docs/2.5.3/media-buy/product-discovery/brief-expectations.mdx similarity index 100% rename from v2.6-rc/docs/media-buy/product-discovery/brief-expectations.mdx rename to dist/docs/2.5.3/media-buy/product-discovery/brief-expectations.mdx diff --git a/v2.6-rc/docs/media-buy/product-discovery/example-briefs.mdx b/dist/docs/2.5.3/media-buy/product-discovery/example-briefs.mdx similarity index 100% rename from v2.6-rc/docs/media-buy/product-discovery/example-briefs.mdx rename to dist/docs/2.5.3/media-buy/product-discovery/example-briefs.mdx diff --git a/v2.6-rc/docs/media-buy/product-discovery/index.mdx b/dist/docs/2.5.3/media-buy/product-discovery/index.mdx similarity index 100% rename from v2.6-rc/docs/media-buy/product-discovery/index.mdx rename to dist/docs/2.5.3/media-buy/product-discovery/index.mdx diff --git a/v2.6-rc/docs/media-buy/product-discovery/media-products.mdx b/dist/docs/2.5.3/media-buy/product-discovery/media-products.mdx similarity index 100% rename from v2.6-rc/docs/media-buy/product-discovery/media-products.mdx rename to dist/docs/2.5.3/media-buy/product-discovery/media-products.mdx diff --git a/v2.6-rc/docs/media-buy/task-reference/create_media_buy.mdx b/dist/docs/2.5.3/media-buy/task-reference/create_media_buy.mdx similarity index 97% rename from v2.6-rc/docs/media-buy/task-reference/create_media_buy.mdx rename to dist/docs/2.5.3/media-buy/task-reference/create_media_buy.mdx index fa138364b3..80001c91ba 100644 --- a/v2.6-rc/docs/media-buy/task-reference/create_media_buy.mdx +++ b/dist/docs/2.5.3/media-buy/task-reference/create_media_buy.mdx @@ -182,8 +182,8 @@ npx adcp \ | `pacing` | string | No | `"even"` (default), `"asap"`, or `"front_loaded"` | | `bid_price` | number | No | Bid price for auction pricing (required when `is_fixed` is false) | | `targeting_overlay` | TargetingOverlay | No | Additional targeting criteria (see [Targeting](/docs/media-buy/advanced-topics/targeting)) | -| `creative_assignments` | CreativeAssignment[] | No | Assign existing library creatives with optional weights and placement targeting | -| `creatives` | CreativeAsset[] | No | Upload new creative assets and assign (`creative_id` must not already exist in library) | +| `creative_ids` | string[] | No | Existing library creative IDs to assign | +| `creatives` | CreativeAsset[] | No | Full creative objects to upload and assign | ## Response @@ -550,7 +550,6 @@ Common errors and resolutions: | `TARGETING_TOO_NARROW` | Targeting yields zero inventory | Broaden geographic or audience criteria | | `POLICY_VIOLATION` | Brand/product violates policy | Review publisher's content policies | | `INVALID_PRICING_OPTION` | pricing_option_id not found | Use ID from product's `pricing_options` | -| `CREATIVE_ID_EXISTS` | Creative ID already exists in library | Use a different `creative_id`, assign existing creatives via `creative_assignments`, or update via `sync_creatives` | Example error response: @@ -1026,7 +1025,6 @@ For complete async handling patterns, see [Task Management](/docs/protocols/task - AXE segments enable advanced audience targeting - Pending states (`working`, `submitted`) are normal, not errors - Orchestrators MUST handle pending states as part of normal workflow -- **Inline creatives**: The `creatives` array creates NEW creatives only. To update existing creatives, use [`sync_creatives`](/docs/media-buy/task-reference/sync_creatives). To assign existing library creatives, use `creative_assignments` instead. ## Policy Compliance diff --git a/v2.6-rc/docs/media-buy/task-reference/get_media_buy_delivery.mdx b/dist/docs/2.5.3/media-buy/task-reference/get_media_buy_delivery.mdx similarity index 100% rename from v2.6-rc/docs/media-buy/task-reference/get_media_buy_delivery.mdx rename to dist/docs/2.5.3/media-buy/task-reference/get_media_buy_delivery.mdx diff --git a/v2.6-rc/docs/media-buy/task-reference/get_products.mdx b/dist/docs/2.5.3/media-buy/task-reference/get_products.mdx similarity index 90% rename from v2.6-rc/docs/media-buy/task-reference/get_products.mdx rename to dist/docs/2.5.3/media-buy/task-reference/get_products.mdx index fa00a940b7..9a877d146e 100644 --- a/v2.6-rc/docs/media-buy/task-reference/get_products.mdx +++ b/dist/docs/2.5.3/media-buy/task-reference/get_products.mdx @@ -129,7 +129,6 @@ asyncio.run(discover_with_filters()) | `brief` | string | No | Natural language description of campaign requirements | | `brand_manifest` | BrandManifest \| string | No | Brand information (inline object or URL). See [Brand Manifest](/docs/creative/brand-manifest) | | `filters` | Filters | No | Structured filters (see below) | -| `property_list` | PropertyListRef | No | [AdCP 3.0] Reference to a property list for filtering. See [Property Lists](/docs/governance/property/tasks/property_lists) | ### Filters Object @@ -173,12 +172,6 @@ Returns an array of `products`, each containing: | `pricing_options` | PricingOption[] | Available pricing models (CPM, CPCV, etc.) | | `brief_relevance` | string | Why this product matches the brief (when brief provided) | -### Response Metadata - -| Field | Type | Description | -|-------|------|-------------| -| `property_list_applied` | boolean | [AdCP 3.0] `true` if the agent filtered products based on the provided `property_list`. Absent or `false` if not provided or not supported. | - **See schema for complete field list**: [`get-products-response.json`](https://adcontextprotocol.org/schemas/v2/media-buy/get-products-response.json) ## Common Scenarios @@ -483,80 +476,6 @@ asyncio.run(discover_standard_formats())
-### Property List Filtering - - -**AdCP 3.0** - Property list filtering requires governance agent support. - - -Filter products to only those available on properties in your approved list: - - - -```javascript JavaScript -import { testAgent } from '@adcp/client/testing'; - -// Filter products by property list from governance agent -const result = await testAgent.getProducts({ - brief: 'Brand-safe inventory for family brand', - brand_manifest: { - name: 'Nike', - url: 'https://nike.com' - }, - property_list: { - agent_url: 'https://governance.example.com', - list_id: 'pl_brand_safe_2024' - } -}); - -if (result.success && result.data) { - // Check if filtering was actually applied - if (result.data.property_list_applied) { - console.log(`Found ${result.data.products.length} products on approved properties`); - } else { - console.log('Agent does not support property list filtering'); - console.log(`Found ${result.data.products.length} products (unfiltered)`); - } -} -``` - -```python Python -import asyncio -from adcp import test_agent - -async def discover_with_property_list(): - # Filter products by property list from governance agent - result = await test_agent.simple.get_products( - brief='Brand-safe inventory for family brand', - brand_manifest={ - 'name': 'Nike', - 'url': 'https://nike.com' - }, - property_list={ - 'agent_url': 'https://governance.example.com', - 'list_id': 'pl_brand_safe_2024' - } - ) - - # Check if filtering was actually applied - if result.get('property_list_applied'): - print(f"Found {len(result['products'])} products on approved properties") - else: - print("Agent does not support property list filtering") - print(f"Found {len(result['products'])} products (unfiltered)") - -asyncio.run(discover_with_property_list()) -``` - - - -**Note**: If `property_list_applied` is absent or `false`, the sales agent did not filter products. This can happen if: -- The agent doesn't support property governance features -- The agent couldn't access the property list -- The property list had no effect on the available inventory - -See [Property Governance](/docs/governance/property/specification) for more on property lists. - ## Error Handling | Error Code | Description | Resolution | diff --git a/v2.6-rc/docs/media-buy/task-reference/index.mdx b/dist/docs/2.5.3/media-buy/task-reference/index.mdx similarity index 100% rename from v2.6-rc/docs/media-buy/task-reference/index.mdx rename to dist/docs/2.5.3/media-buy/task-reference/index.mdx diff --git a/v2.6-rc/docs/media-buy/task-reference/list_authorized_properties.mdx b/dist/docs/2.5.3/media-buy/task-reference/list_authorized_properties.mdx similarity index 99% rename from v2.6-rc/docs/media-buy/task-reference/list_authorized_properties.mdx rename to dist/docs/2.5.3/media-buy/task-reference/list_authorized_properties.mdx index 55bd3fcf87..5e7cb8ea9d 100644 --- a/v2.6-rc/docs/media-buy/task-reference/list_authorized_properties.mdx +++ b/dist/docs/2.5.3/media-buy/task-reference/list_authorized_properties.mdx @@ -498,6 +498,6 @@ After discovering authorized properties: ## Learn More -- [adagents.json Specification](/docs/governance/property/adagents) - Publisher authorization file format +- [adagents.json Specification](/docs/media-buy/capability-discovery/adagents) - Publisher authorization file format - [Property Schema](https://adcontextprotocol.org/schemas/v2/core/property.json) - Property definition structure - [Authorization Guide](/docs/reference/authentication) - How authorization works in AdCP diff --git a/v2.6-rc/docs/media-buy/task-reference/list_creative_formats.mdx b/dist/docs/2.5.3/media-buy/task-reference/list_creative_formats.mdx similarity index 100% rename from v2.6-rc/docs/media-buy/task-reference/list_creative_formats.mdx rename to dist/docs/2.5.3/media-buy/task-reference/list_creative_formats.mdx diff --git a/v2.6-rc/docs/media-buy/task-reference/list_creatives.mdx b/dist/docs/2.5.3/media-buy/task-reference/list_creatives.mdx similarity index 92% rename from v2.6-rc/docs/media-buy/task-reference/list_creatives.mdx rename to dist/docs/2.5.3/media-buy/task-reference/list_creatives.mdx index 46e76a9d7d..1f5c3804de 100644 --- a/v2.6-rc/docs/media-buy/task-reference/list_creatives.mdx +++ b/dist/docs/2.5.3/media-buy/task-reference/list_creatives.mdx @@ -46,16 +46,14 @@ The `list_creatives` task provides comprehensive search and filtering capabiliti ```json { "filters": { - "formats": ["video"], // Filter by format types - "statuses": ["approved", "pending_review"] // Filter by statuses + "format": "video", // Single format + "formats": ["video", "audio"], // Multiple formats + "status": "approved", // Single status + "statuses": ["approved", "pending_review"] // Multiple statuses } } ``` - -**Archived creatives are excluded by default.** To include archived creatives in results, explicitly filter by `status: "archived"` or include `"archived"` in the `statuses` array. - - ### Tag-Based Filtering ```json @@ -96,7 +94,8 @@ The `list_creatives` task provides comprehensive search and filtering capabiliti ```json { "filters": { - "assigned_to_packages": ["pkg_ctv_001"], // Assigned to any of these packages + "assigned_to_package": "pkg_ctv_001", // Assigned to specific package + "assigned_to_packages": ["pkg_001", "pkg_002"], // Assigned to any of these packages "media_buy_ids": ["mb_123", "mb_456"], // Assigned to any of these media buys "buyer_refs": ["campaign_abc", "campaign_xyz"], // Assigned to media buys with these buyer references "unassigned": true // Unassigned creatives only @@ -193,8 +192,7 @@ The response provides comprehensive creative data with optional enrichment: "status_summary": { "approved": 20, "pending_review": 3, - "rejected": 2, - "archived": 5 + "rejected": 2 } } ``` @@ -208,8 +206,8 @@ List all approved video creatives: ```json { "filters": { - "formats": ["video"], - "statuses": ["approved"] + "format": "video", + "status": "approved" }, "sort": { "field": "created_date", @@ -248,7 +246,7 @@ Get creatives ready for assignment to new campaigns: { "filters": { "unassigned": true, - "statuses": ["approved"] + "status": "approved" }, "sort": { "field": "created_date", @@ -267,7 +265,7 @@ Find all creatives assigned to a specific package: ```json { "filters": { - "assigned_to_packages": ["pkg_ctv_premium_001"] + "assigned_to_package": "pkg_ctv_premium_001" }, "include_assignments": true, "include_performance": true, @@ -287,7 +285,7 @@ Find mobile-optimized creatives across multiple formats: "filters": { "formats": ["display_320x50", "video_9x16_mobile", "display_300x250"], "tags_any": ["mobile_optimized", "responsive"], - "statuses": ["approved"] + "status": "approved" }, "sort": { "field": "updated_date", @@ -305,7 +303,7 @@ Get minimal creative data for UI dropdown: "fields": ["creative_id", "name", "format", "status"], "include_assignments": false, "filters": { - "statuses": ["approved"] + "status": "approved" }, "sort": { "field": "name", @@ -360,7 +358,7 @@ Find all creatives used in specific media buys or campaigns: { "filters": { "media_buy_ids": ["mb_summer_2025", "mb_spring_2025"], - "statuses": ["approved"] + "status": "approved" }, "include_assignments": true, "include_performance": true, @@ -389,22 +387,6 @@ Search creatives across related campaigns by buyer reference: } ``` -### Example 11: Query Archived Creatives - -View archived creatives (excluded from default queries): - -```json -{ - "filters": { - "status": "archived" - }, - "sort": { - "field": "updated_date", - "direction": "desc" - } -} -``` - ## Query Optimization Tips ### 1. Use Specific Filters @@ -447,7 +429,7 @@ View archived creatives (excluded from default queries): ```json { "filters": { - "statuses": ["approved"], + "status": "approved", "unassigned": true }, "sort": { "field": "created_date", "direction": "desc" } @@ -520,7 +502,7 @@ For queries returning very large result sets: // Get lightweight creative list for dropdown const response = await adcp.list_creatives({ fields: ["creative_id", "name", "format"], - filters: { statuses: ["approved"] }, + filters: { status: "approved" }, sort: { field: "name", direction: "asc" }, include_assignments: false }); @@ -543,12 +525,12 @@ const response = await adcp.list_creatives({ ### Assignment Management -```javascript +```javascript // Find unassigned creatives ready for new campaigns const response = await adcp.list_creatives({ filters: { unassigned: true, - statuses: ["approved"], + status: "approved", formats: ["video", "display"] }, sort: { field: "created_date", direction: "desc" } diff --git a/v2.6-rc/docs/media-buy/task-reference/provide_performance_feedback.mdx b/dist/docs/2.5.3/media-buy/task-reference/provide_performance_feedback.mdx similarity index 100% rename from v2.6-rc/docs/media-buy/task-reference/provide_performance_feedback.mdx rename to dist/docs/2.5.3/media-buy/task-reference/provide_performance_feedback.mdx diff --git a/v2.6-rc/docs/media-buy/task-reference/sync_creatives.mdx b/dist/docs/2.5.3/media-buy/task-reference/sync_creatives.mdx similarity index 96% rename from v2.6-rc/docs/media-buy/task-reference/sync_creatives.mdx rename to dist/docs/2.5.3/media-buy/task-reference/sync_creatives.mdx index 30a5182714..e5133c59d2 100644 --- a/v2.6-rc/docs/media-buy/task-reference/sync_creatives.mdx +++ b/dist/docs/2.5.3/media-buy/task-reference/sync_creatives.mdx @@ -106,7 +106,7 @@ asyncio.run(main()) | `assignments` | object | No | Map of creative_id to array of package_ids for bulk assignment | | `dry_run` | boolean | No | When true, preview changes without applying them (default: false) | | `validation_mode` | string | No | Validation strictness: `"strict"` (default) or `"lenient"` | -| `delete_missing` | boolean | No | When true, creatives not in this sync are archived (default: false). Cannot delete creatives assigned to active, non-paused packages. | +| `delete_missing` | boolean | No | When true, creatives not in this sync are archived (default: false) | ### Creative Object @@ -651,11 +651,11 @@ The operation status (`completed`) means the review process finished. Individual | `PACKAGE_NOT_FOUND` | Package ID doesn't exist in media buy | Verify `package_id` from `create_media_buy` response | | `BRAND_SAFETY_VIOLATION` | Creative failed brand safety scan | Review content against publisher's brand safety guidelines | | `FORMAT_MISMATCH` | Assets don't match format requirements | Verify asset types and specifications match format definition | -| `CREATIVE_IN_ACTIVE_DELIVERY` | Creative is assigned to an active, non-paused package (blocks updates and `delete_missing` deletions) | Pause the package first, or create a new creative version | +| `DUPLICATE_CREATIVE_ID` | Creative ID already exists in different media buy | Use unique `creative_id` or sync to correct media buy | ## Best Practices -1. **Use upsert semantics** - Same `creative_id` updates existing creative rather than creating duplicates. This allows iterative creative development. Note: updates are blocked for creatives in active delivery (see #7). +1. **Use upsert semantics** - Same `creative_id` updates existing creative rather than creating duplicates. This allows iterative creative development. 2. **Validate first** - Use `dry_run: true` to catch errors before actual upload. This saves bandwidth and processing time. @@ -667,8 +667,6 @@ The operation status (`completed`) means the review process finished. Individual 6. **Check format support** - Use `list_creative_formats` to verify product supports your creative formats before uploading. -7. **Active delivery protection** - Creatives assigned to active, non-paused packages cannot be updated or deleted via `delete_missing`. Pause the package first, unassign the creative via `update_media_buy`, or create a new creative with a different `creative_id`. - ## Next Steps - [list_creative_formats](/docs/media-buy/task-reference/list_creative_formats) - Check supported formats before upload diff --git a/v2.6-rc/docs/media-buy/task-reference/update_media_buy.mdx b/dist/docs/2.5.3/media-buy/task-reference/update_media_buy.mdx similarity index 89% rename from v2.6-rc/docs/media-buy/task-reference/update_media_buy.mdx rename to dist/docs/2.5.3/media-buy/task-reference/update_media_buy.mdx index 0dd78ea270..237b6847e7 100644 --- a/v2.6-rc/docs/media-buy/task-reference/update_media_buy.mdx +++ b/dist/docs/2.5.3/media-buy/task-reference/update_media_buy.mdx @@ -149,25 +149,11 @@ asyncio.run(create_and_pause_campaign()) | `end_time` | string | No | Updated campaign end time | | `paused` | boolean | No | Pause/resume entire media buy (`true` = paused, `false` = active) | | `packages` | PackageUpdate[] | No | Package-level updates (see below) | -| `reporting_webhook` | object | No | Update reporting webhook configuration (see below) | -| `push_notification_config` | object | No | Webhook for async operation notifications | +| `creatives` | CreativeAsset[] | No | Upload and assign new creative assets inline | +| `creative_assignments` | CreativeAssignment[] | No | Update creative rotation weights and placement targeting | *Either `media_buy_id` OR `buyer_ref` is required (not both) -### Reporting Webhook Object - -Configure automated delivery reporting for this media buy: - -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `url` | string | Yes | Webhook endpoint URL | -| `authentication` | object | Yes | Auth config with `schemes` and `credentials` | -| `reporting_frequency` | string | Yes | `hourly`, `daily`, or `monthly` | -| `requested_metrics` | string[] | No | Specific metrics to include (defaults to all) | -| `token` | string | No | Client token for validation (min 16 chars) | - -**Note**: `reporting_webhook` configures ongoing campaign reporting. `push_notification_config` is for async operation notifications (e.g., "notify me when this update completes"). - ### Package Update Object | Parameter | Type | Description | @@ -180,8 +166,7 @@ Configure automated delivery reporting for this media buy: | `pacing` | string | Updated pacing strategy | | `bid_price` | number | Updated bid price (auction products only) | | `targeting_overlay` | TargetingOverlay | Updated targeting restrictions | -| `creative_assignments` | CreativeAssignment[] | Replace assigned creatives with optional weights and placement targeting | -| `creatives` | CreativeAsset[] | Upload and assign new creatives inline (must not exist in library) | +| `creative_ids` | string[] | Replace assigned creatives | *Either `package_id` OR `buyer_ref` is required for each package update @@ -387,7 +372,7 @@ asyncio.run(update_targeting()) ### Replace Creatives -Swap out creative assignments for a package: +Swap out creative assets for a package: @@ -399,10 +384,7 @@ const result = await testAgent.updateMediaBuy({ media_buy_id: 'mb_12345', packages: [{ buyer_ref: 'ctv_package', - creative_assignments: [ - { creative_id: 'creative_video_v2' }, - { creative_id: 'creative_display_v2', weight: 60 } - ] + creative_ids: ['creative_video_v2', 'creative_display_v2'] }] }); @@ -433,10 +415,7 @@ async def replace_creatives(): packages=[ { 'buyer_ref': 'ctv_package', - 'creative_assignments': [ - {'creative_id': 'creative_video_v2'}, - {'creative_id': 'creative_display_v2', 'weight': 60} - ] + 'creative_ids': ['creative_video_v2', 'creative_display_v2'] } ] ) @@ -534,7 +513,6 @@ asyncio.run(update_multiple_packages()) ✅ **Can update:** - Start/end times (subject to seller approval) - Campaign status (active/paused) -- Reporting webhook configuration (URL, frequency, metrics) ❌ **Cannot update:** - Media buy ID @@ -570,7 +548,6 @@ Common errors and resolutions: | `BUDGET_INSUFFICIENT` | New budget below minimum | Increase budget amount | | `POLICY_VIOLATION` | Update violates content policy | Review policy requirements | | `INVALID_STATE` | Operation not allowed in current state | Check campaign status | -| `CREATIVE_ID_EXISTS` | Creative ID already exists in library | Use a different `creative_id`, assign existing creatives via `creative_assignments`, or update via `sync_creatives` | Example error response: @@ -619,16 +596,13 @@ Only specified fields are updated - omitted fields remain unchanged: } ``` -**Array replacement**: When updating arrays (like `creative_assignments`), provide the complete new array: +**Array replacement**: When updating arrays (like `creative_ids`), provide the complete new array: ```json { "packages": [{ "buyer_ref": "ctv_package", - "creative_assignments": [ - { "creative_id": "creative_video_v2" }, - { "creative_id": "creative_display_v2", "weight": 60 } - ] + "creative_ids": ["creative_video_v2", "creative_display_v2"] }] } ``` @@ -704,14 +678,13 @@ Check `affected_packages` in response to confirm changes were applied correctly. - Pending states (`working`, `submitted`) are normal, not errors - Orchestrators MUST handle pending states as part of normal workflow - `implementation_date` indicates when changes take effect (null if pending approval) -- **Inline creatives**: The `creatives` array creates NEW creatives only. To update existing creatives, use [`sync_creatives`](/docs/media-buy/task-reference/sync_creatives). To assign existing library creatives, use `creative_assignments` in the Package Update object. ## Next Steps After updating a media buy: 1. **Verify Changes**: Use [`get_media_buy_delivery`](/docs/media-buy/task-reference/get_media_buy_delivery) to confirm updates -2. **Upload New Creatives**: Use [`sync_creatives`](/docs/media-buy/task-reference/sync_creatives) if creative assignments changed +2. **Upload New Creatives**: Use [`sync_creatives`](/docs/media-buy/task-reference/sync_creatives) if creative_ids changed 3. **Monitor Performance**: Track impact of changes on campaign metrics 4. **Optimize Further**: Use [`provide_performance_feedback`](/docs/media-buy/task-reference/provide_performance_feedback) for ongoing optimization diff --git a/v2.6-rc/docs/protocols/a2a-guide.mdx b/dist/docs/2.5.3/protocols/a2a-guide.mdx similarity index 94% rename from v2.6-rc/docs/protocols/a2a-guide.mdx rename to dist/docs/2.5.3/protocols/a2a-guide.mdx index f66867dc49..8bfe9b4f54 100644 --- a/v2.6-rc/docs/protocols/a2a-guide.mdx +++ b/dist/docs/2.5.3/protocols/a2a-guide.mdx @@ -711,51 +711,32 @@ console.log('Examples:', getProductsSkill.examples); ] } ], - "extensions": [ - { - "uri": "https://adcontextprotocol.org/extensions/adcp", - "description": "AdCP media buying protocol support", - "required": false, - "params": { - "adcp_version": "2.6.0", - "protocols_supported": ["media_buy"], - "extensions_supported": ["sustainability"] - } + "extensions": { + "adcp": { + "adcp_version": "2.4.0", + "protocols_supported": ["media_buy"] } - ] + } } ``` ### AdCP Extension -**Recommended**: Include the AdCP extension in your agent card's `extensions` array to declare AdCP support programmatically. - -The A2A protocol uses an `extensions` array where each extension has: -- **`uri`**: Extension identifier (use `https://adcontextprotocol.org/extensions/adcp`) -- **`description`**: Human-readable description of how you use AdCP -- **`required`**: Whether clients must support this extension (typically `false` for AdCP) -- **`params`**: AdCP-specific configuration (see schema below) +**Recommended**: Include the `extensions.adcp` field in your agent card to declare AdCP support programmatically. ```javascript // Check if agent supports AdCP const agentCard = await fetch('https://sales.example.com/.well-known/agent.json') .then(r => r.json()); -// Find the AdCP extension in the extensions array -const adcpExt = agentCard.extensions?.find( - ext => ext.uri === 'https://adcontextprotocol.org/extensions/adcp' -); - -if (adcpExt) { - console.log('AdCP Version:', adcpExt.params.adcp_version); - console.log('Supported domains:', adcpExt.params.protocols_supported); +if (agentCard.extensions?.adcp) { + console.log('AdCP Version:', agentCard.extensions.adcp.adcp_version); + console.log('Supported domains:', agentCard.extensions.adcp.protocols_supported); // ["media_buy", "creative", "signals"] - console.log('Typed extensions:', adcpExt.params.extensions_supported); - // ["sustainability"] } ``` -**Extension Params Schema**: See the [AdCP extension schema](https://adcontextprotocol.org/schemas/v2/protocols/adcp-extension.json) for the complete `params` specification. +**Extension Structure**: See the [AdCP extension schema](https://adcontextprotocol.org/schemas/v2/protocols/adcp-extension.json) for complete specification. **Benefits**: - Clients can discover AdCP capabilities without making test calls diff --git a/v2.6-rc/docs/protocols/a2a-response-format.mdx b/dist/docs/2.5.3/protocols/a2a-response-format.mdx similarity index 100% rename from v2.6-rc/docs/protocols/a2a-response-format.mdx rename to dist/docs/2.5.3/protocols/a2a-response-format.mdx diff --git a/v2.6-rc/docs/protocols/context-management.mdx b/dist/docs/2.5.3/protocols/context-management.mdx similarity index 92% rename from v2.6-rc/docs/protocols/context-management.mdx rename to dist/docs/2.5.3/protocols/context-management.mdx index 5c623bfc4a..8ba34f6505 100644 --- a/v2.6-rc/docs/protocols/context-management.mdx +++ b/dist/docs/2.5.3/protocols/context-management.mdx @@ -169,9 +169,9 @@ Response (application-level context is repeated inside the payload): } ``` -![Application Context Lifecycle 01](./initator-context-lifecycle-01.png) +Application context lifecycle diagram showing initiator request flow -![Application Context Lifecycle 02](./initator-context-lifecycle-02.png) +Application context lifecycle diagram showing webhook response flow Webhook updates include the same application-level `context` inside the webhook `result` payload. diff --git a/v2.6-rc/docs/protocols/core-concepts.mdx b/dist/docs/2.5.3/protocols/core-concepts.mdx similarity index 100% rename from v2.6-rc/docs/protocols/core-concepts.mdx rename to dist/docs/2.5.3/protocols/core-concepts.mdx diff --git a/v2.6-rc/docs/protocols/envelope-examples.mdx b/dist/docs/2.5.3/protocols/envelope-examples.mdx similarity index 100% rename from v2.6-rc/docs/protocols/envelope-examples.mdx rename to dist/docs/2.5.3/protocols/envelope-examples.mdx diff --git a/v2.6-rc/docs/protocols/error-handling.mdx b/dist/docs/2.5.3/protocols/error-handling.mdx similarity index 100% rename from v2.6-rc/docs/protocols/error-handling.mdx rename to dist/docs/2.5.3/protocols/error-handling.mdx diff --git a/v2.6-rc/docs/protocols/getting-started.mdx b/dist/docs/2.5.3/protocols/getting-started.mdx similarity index 100% rename from v2.6-rc/docs/protocols/getting-started.mdx rename to dist/docs/2.5.3/protocols/getting-started.mdx diff --git a/v2.6-rc/docs/protocols/initator-context-lifecycle-01.png b/dist/docs/2.5.3/protocols/initator-context-lifecycle-01.png similarity index 100% rename from v2.6-rc/docs/protocols/initator-context-lifecycle-01.png rename to dist/docs/2.5.3/protocols/initator-context-lifecycle-01.png diff --git a/v2.6-rc/docs/protocols/initator-context-lifecycle-02.png b/dist/docs/2.5.3/protocols/initator-context-lifecycle-02.png similarity index 100% rename from v2.6-rc/docs/protocols/initator-context-lifecycle-02.png rename to dist/docs/2.5.3/protocols/initator-context-lifecycle-02.png diff --git a/v2.6-rc/docs/protocols/mcp-guide.mdx b/dist/docs/2.5.3/protocols/mcp-guide.mdx similarity index 91% rename from v2.6-rc/docs/protocols/mcp-guide.mdx rename to dist/docs/2.5.3/protocols/mcp-guide.mdx index a8581b776e..c3303454dd 100644 --- a/v2.6-rc/docs/protocols/mcp-guide.mdx +++ b/dist/docs/2.5.3/protocols/mcp-guide.mdx @@ -632,60 +632,22 @@ const adcpTools = tools.filter(t => t.name.startsWith('adcp_') || ['get_products', 'create_media_buy'].includes(t.name)); ``` -### AdCP Extension via MCP Server Card +### AdCP Extension (Future) -MCP servers can declare AdCP support via a server card at `/.well-known/mcp.json` (or `/.well-known/server.json`). AdCP-specific metadata goes in the `_meta` field using the `adcontextprotocol.org` namespace. +**Status**: MCP server cards are expected in a future MCP release. When available, AdCP servers will include the AdCP extension. ```json { - "name": "io.adcontextprotocol/media-buy-agent", - "version": "1.0.0", - "title": "AdCP Media Buy Agent", - "description": "AI-powered media buying agent implementing AdCP", - "tools": [ - { "name": "get_products" }, - { "name": "create_media_buy" }, - { "name": "list_creative_formats" } - ], - "_meta": { - "adcontextprotocol.org": { - "adcp_version": "2.6.0", - "protocols_supported": ["media_buy"], - "extensions_supported": ["sustainability"] + "extensions": { + "adcp": { + "adcp_version": "2.4.0", + "protocols_supported": ["media_buy", "creative", "signals"] } } } ``` -**Discovering AdCP support:** - -```javascript -// Check both possible locations for MCP server card -const serverCard = await fetch('https://sales.example.com/.well-known/mcp.json') - .then(r => r.ok ? r.json() : null) - .catch(() => null) - || await fetch('https://sales.example.com/.well-known/server.json') - .then(r => r.json()); - -// Check for AdCP metadata -const adcpMeta = serverCard?._meta?.['adcontextprotocol.org']; - -if (adcpMeta) { - console.log('AdCP Version:', adcpMeta.adcp_version); - console.log('Supported domains:', adcpMeta.protocols_supported); - // ["media_buy", "creative", "signals"] - console.log('Typed extensions:', adcpMeta.extensions_supported); - // ["sustainability"] -} -``` - -**Benefits:** -- Clients can discover AdCP capabilities without making test calls -- Declare which protocol domains you implement (media_buy, creative, signals) -- Declare which [typed extensions](/docs/reference/extensions-and-context#typed-extensions) you support -- Enable compatibility checks based on version - -**Note:** The `_meta` field uses reverse DNS namespacing per the [MCP server.json spec](https://github.com/modelcontextprotocol/registry/blob/main/docs/reference/server-json/generic-server-json.md). AdCP servers should support both `/.well-known/mcp.json` and `/.well-known/server.json` locations. +This will allow clients to programmatically discover which AdCP version and protocol domains an MCP server implements. See the [AdCP extension schema](https://adcontextprotocol.org/schemas/v2/protocols/adcp-extension.json) for specification details. ### Parameter Validation ```javascript diff --git a/v2.6-rc/docs/protocols/protocol-comparison.mdx b/dist/docs/2.5.3/protocols/protocol-comparison.mdx similarity index 100% rename from v2.6-rc/docs/protocols/protocol-comparison.mdx rename to dist/docs/2.5.3/protocols/protocol-comparison.mdx diff --git a/v2.6-rc/docs/protocols/task-management.mdx b/dist/docs/2.5.3/protocols/task-management.mdx similarity index 100% rename from v2.6-rc/docs/protocols/task-management.mdx rename to dist/docs/2.5.3/protocols/task-management.mdx diff --git a/v2.6-rc/docs/quickstart.mdx b/dist/docs/2.5.3/quickstart.mdx similarity index 100% rename from v2.6-rc/docs/quickstart.mdx rename to dist/docs/2.5.3/quickstart.mdx diff --git a/v2.6-rc/docs/reference/ad-tech-primer.mdx b/dist/docs/2.5.3/reference/ad-tech-primer.mdx similarity index 100% rename from v2.6-rc/docs/reference/ad-tech-primer.mdx rename to dist/docs/2.5.3/reference/ad-tech-primer.mdx diff --git a/v2.6-rc/docs/reference/adcp-ecosystem.mdx b/dist/docs/2.5.3/reference/adcp-ecosystem.mdx similarity index 100% rename from v2.6-rc/docs/reference/adcp-ecosystem.mdx rename to dist/docs/2.5.3/reference/adcp-ecosystem.mdx diff --git a/v2.6-rc/docs/reference/authentication.mdx b/dist/docs/2.5.3/reference/authentication.mdx similarity index 100% rename from v2.6-rc/docs/reference/authentication.mdx rename to dist/docs/2.5.3/reference/authentication.mdx diff --git a/v2.6-rc/docs/reference/changelog.mdx b/dist/docs/2.5.3/reference/changelog.mdx similarity index 100% rename from v2.6-rc/docs/reference/changelog.mdx rename to dist/docs/2.5.3/reference/changelog.mdx diff --git a/v2.6-rc/docs/reference/creative-quick-reference.mdx b/dist/docs/2.5.3/reference/creative-quick-reference.mdx similarity index 100% rename from v2.6-rc/docs/reference/creative-quick-reference.mdx rename to dist/docs/2.5.3/reference/creative-quick-reference.mdx diff --git a/v2.6-rc/docs/reference/data-models.mdx b/dist/docs/2.5.3/reference/data-models.mdx similarity index 99% rename from v2.6-rc/docs/reference/data-models.mdx rename to dist/docs/2.5.3/reference/data-models.mdx index 0e66f3fc07..7f88e4e86a 100644 --- a/v2.6-rc/docs/reference/data-models.mdx +++ b/dist/docs/2.5.3/reference/data-models.mdx @@ -79,7 +79,7 @@ interface CreativeAsset { name: string; format: string; url?: string; - status: 'processing' | 'approved' | 'rejected' | 'pending_review' | 'archived'; + status: 'processing' | 'approved' | 'rejected' | 'pending_review'; compliance?: { status: string; issues?: string[]; @@ -166,7 +166,7 @@ type DeliveryType = 'guaranteed' | 'non_guaranteed'; type MediaBuyStatus = 'pending_activation' | 'active' | 'paused' | 'completed'; // Creative Status - Schema: /schemas/v2/enums/creative-status.json -type CreativeStatus = 'processing' | 'approved' | 'rejected' | 'pending_review' | 'archived'; +type CreativeStatus = 'processing' | 'approved' | 'rejected' | 'pending_review'; // Pacing - Schema: /schemas/v2/enums/pacing.json type Pacing = 'even' | 'asap' | 'front_loaded'; diff --git a/v2.6-rc/docs/reference/error-codes.mdx b/dist/docs/2.5.3/reference/error-codes.mdx similarity index 89% rename from v2.6-rc/docs/reference/error-codes.mdx rename to dist/docs/2.5.3/reference/error-codes.mdx index 0eac0041c3..0132e64cdf 100644 --- a/v2.6-rc/docs/reference/error-codes.mdx +++ b/dist/docs/2.5.3/reference/error-codes.mdx @@ -425,61 +425,6 @@ Request exceeded maximum processing time. **Resolution**: Refine request parameters or retry. -## Content Standards Errors - -### STANDARDS_NOT_FOUND -Specified standards ID doesn't exist. - -**Example**: -```json -{ - "$schema": "https://adcontextprotocol.org/schemas/v2/core/error.json", - "code": "STANDARDS_NOT_FOUND", - "message": "No standards found with ID 'invalid_id'", - "details": { - "standards_id": "invalid_id" - } -} -``` - -**Resolution**: Use `list_content_standards` to find valid standards IDs. - -### STANDARDS_IN_USE -Cannot delete standards that are referenced by active media buys. - -**Example**: -```json -{ - "$schema": "https://adcontextprotocol.org/schemas/v2/core/error.json", - "code": "STANDARDS_IN_USE", - "message": "Cannot delete standards 'nike_emea_safety' - currently referenced by active media buys", - "details": { - "standards_id": "nike_emea_safety", - "active_media_buy_count": 3 - } -} -``` - -**Resolution**: Wait for media buys to complete before deleting. - -### STANDARDS_SCOPE_CONFLICT -New standards configuration conflicts with existing standards for the same scope. - -**Example**: -```json -{ - "$schema": "https://adcontextprotocol.org/schemas/v2/core/error.json", - "code": "STANDARDS_SCOPE_CONFLICT", - "message": "Standards already exist for brand 'nike' in countries ['GB', 'DE']", - "details": { - "conflicting_standards_id": "nike_emea_safety", - "overlapping_countries": ["GB", "DE"] - } -} -``` - -**Resolution**: Update existing standards or narrow scope to avoid overlap. - ## Data Errors ### DATA_QUALITY_ISSUE @@ -561,10 +506,7 @@ const PERMANENT_ERRORS = [ 'INSUFFICIENT_PERMISSIONS', 'SEGMENT_NOT_FOUND', 'PLATFORM_UNAUTHORIZED', - 'UNSUPPORTED_VERSION', - 'STANDARDS_NOT_FOUND', - 'STANDARDS_IN_USE', - 'STANDARDS_SCOPE_CONFLICT' + 'UNSUPPORTED_VERSION' ]; function isRetryable(errorCode: string): boolean { diff --git a/v2.6-rc/docs/reference/extensions-and-context.mdx b/dist/docs/2.5.3/reference/extensions-and-context.mdx similarity index 56% rename from v2.6-rc/docs/reference/extensions-and-context.mdx rename to dist/docs/2.5.3/reference/extensions-and-context.mdx index e29ec563c3..48484c0201 100644 --- a/v2.6-rc/docs/reference/extensions-and-context.mdx +++ b/dist/docs/2.5.3/reference/extensions-and-context.mdx @@ -181,213 +181,6 @@ Without namespacing: - Impossible to support multiple platforms simultaneously - Harder to deprecate platform-specific features -## Typed Extensions - -AdCP supports formal JSON schemas for extensions, enabling type safety and validation. Typed extensions are published in the `/schemas/extensions/` directory and can be declared in agent cards. - -### How Typed Extensions Work - -Typed extensions provide a middle ground between untyped vendor extensions and core AdCP fields: - -- **Untyped extensions** (`ext.vendor.*`) - Any JSON, no validation, vendor-specific -- **Typed extensions** (`ext.sustainability.*`) - Formal schema, validated, cross-vendor -- **Core fields** - Part of AdCP specification, required for interoperability - -Typed extensions enable SDK code generation, schema validation, and cross-vendor interoperability while remaining optional. - -### Extension Schema Registry - -The registry of available typed extensions is auto-generated from extension files: -- **Registry**: `/schemas/v1/extensions/index.json` -- **Extension schemas**: `/schemas/v1/extensions/{namespace}.json` -- **Meta schema**: `/schemas/v1/extensions/extension-meta.json` - -Each versioned schema path (`/schemas/v2.5/`, `/schemas/v2.6/`) includes only extensions valid for that version, based on the `valid_from` and `valid_until` fields in each extension. - -### Extension Versioning - -Extensions are versioned independently of the AdCP specification: - -```json -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/extensions/sustainability.json", - "title": "Sustainability Extension", - "description": "Carbon footprint and green certification data", - "valid_from": "2.5", - "valid_until": "4.0", - "docs_url": "https://adcontextprotocol.org/docs/extensions/sustainability", - "type": "object", - "properties": { - "carbon_kg_per_impression": { "type": "number" }, - "certified_green": { "type": "boolean" } - } -} -``` - -- **`valid_from`** (required): Minimum AdCP version this extension works with (e.g., `"2.5"`) -- **`valid_until`** (optional): Last AdCP version this extension works with. Omit if still valid. - -This allows extensions to be backported to earlier AdCP versions and deprecated gracefully. - -### Declaring Extension Support - -Agents declare which typed extensions they support in their discovery metadata. The location depends on the protocol: - -#### A2A Agent Cards - -A2A agents declare AdCP support in the `extensions` array at `/.well-known/agent.json`: - -```json -{ - "name": "AdCP Media Buy Agent", - "skills": [{ "name": "get_products" }, { "name": "create_media_buy" }], - "extensions": [ - { - "uri": "https://adcontextprotocol.org/extensions/adcp", - "description": "AdCP media buying protocol support", - "required": false, - "params": { - "adcp_version": "2.6.0", - "protocols_supported": ["media_buy"], - "extensions_supported": ["sustainability"] - } - } - ] -} -``` - -See the [A2A Guide](/docs/protocols/a2a-guide#adcp-extension) for complete details. - -#### MCP Server Cards - -MCP servers declare AdCP support via the `_meta` field at `/.well-known/mcp.json` or `/.well-known/server.json`: - -```json -{ - "name": "io.adcontextprotocol/media-buy-agent", - "tools": [{ "name": "get_products" }, { "name": "create_media_buy" }], - "_meta": { - "adcontextprotocol.org": { - "adcp_version": "2.6.0", - "protocols_supported": ["media_buy"], - "extensions_supported": ["sustainability"] - } - } -} -``` - -See the [MCP Guide](/docs/protocols/mcp-guide#adcp-extension-via-mcp-server-card) for complete details. - -#### Extension Params Schema - -Both protocols use the same params structure, defined in the [AdCP extension schema](https://adcontextprotocol.org/schemas/v2/protocols/adcp-extension.json): -- **`adcp_version`** (required): Semantic version of AdCP implemented (e.g., "2.6.0") -- **`protocols_supported`** (required): Array of protocol domains (media_buy, creative, signals) -- **`extensions_supported`** (optional): Array of typed extension namespaces - -When an agent declares support for an extension, clients can expect: -- The agent will accept and populate `ext.{namespace}` fields conforming to that extension's schema -- Data in `ext.{namespace}` is strongly typed and can be validated -- SDK code generation can produce type-safe interfaces for the extension - -### Using Typed Extensions - -When an agent supports a typed extension, you can include and expect data in the corresponding namespace: - -```json -{ - "product_id": "premium_ctv", - "name": "Premium CTV Package", - "ext": { - "sustainability": { - "carbon_kg_per_impression": 0.0012, - "certified_green": true - } - } -} -``` - -### Creating a Typed Extension - -To create a typed extension: - -1. **Create the extension file** at `/schemas/extensions/{namespace}.json` -2. **Follow the meta schema** defined in `/schemas/extensions/extension-meta.json` -3. **Set `valid_from`** to the minimum AdCP version your extension requires -4. **Add documentation** via the `docs_url` field - -Example extension file: - -```json -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/extensions/sustainability.json", - "title": "Sustainability Extension", - "description": "Carbon footprint and green certification data for ad products", - "valid_from": "2.5", - "docs_url": "https://adcontextprotocol.org/docs/extensions/sustainability", - "type": "object", - "properties": { - "carbon_kg_per_impression": { - "type": "number", - "description": "Estimated CO2 emissions per impression in kilograms" - }, - "certified_green": { - "type": "boolean", - "description": "Whether the inventory is certified by a green advertising program" - }, - "certification_provider": { - "type": "string", - "description": "Name of the green certification provider" - } - } -} -``` - -The build process auto-discovers extension files and includes them in the appropriate versioned schema builds. - -### Proposing Typed Extensions - -To propose a typed extension for inclusion in AdCP: - -1. **Validate in production first** - Use vendor-namespaced extensions (`ext.yourcompany.*`) to prove value -2. **Document the schema** - Define clear property names, types, and descriptions -3. **Gather adoption evidence** - Show multiple implementations or strong demand -4. **Submit an RFC** - Propose the extension with schema and use cases -5. **If accepted** - Extension is added to `/schemas/extensions/` with appropriate `valid_from` - -### Reserved Namespaces - -The following namespaces are reserved and cannot be used for typed extensions: -- `adcp`, `core`, `protocol`, `schema`, `meta`, `ext`, `context` - -These are reserved to prevent confusion with core AdCP concepts. - -### Extension Deprecation Policy - -#### When Extensions May Be Deprecated - -1. **Superseded** - A better extension exists with a documented migration path -2. **Promoted to core** - The extension becomes a core AdCP field -3. **Low adoption** - Insufficient usage across implementations -4. **Incompatible** - Breaking changes in AdCP require removal - -#### Deprecation Process - -1. Set `valid_until` to current version + 1 minor release (minimum grace period) -2. Announce deprecation in CHANGELOG -3. Publish migration guide if replacement exists -4. Add deprecation warning to extension docs -5. Extension removed from builds after `valid_until` version - -#### Emergency Deprecation - -Security issues may require immediate deprecation: -- `valid_until` set to current version -- Security advisory published -- Patch release issued - ## Proposing Spec Additions If your extension field represents **common ad tech functionality** that would benefit all AdCP implementations: diff --git a/v2.6-rc/docs/reference/glossary.mdx b/dist/docs/2.5.3/reference/glossary.mdx similarity index 89% rename from v2.6-rc/docs/reference/glossary.mdx rename to dist/docs/2.5.3/reference/glossary.mdx index e069d90d63..dbe1fec44a 100644 --- a/v2.6-rc/docs/reference/glossary.mdx +++ b/dist/docs/2.5.3/reference/glossary.mdx @@ -67,11 +67,14 @@ Size unit representing unique device identifiers (cookies, mobile IDs) - typical **Device Type** (Media Buy Protocol) Targeting dimension for platform types: mobile, desktop, tablet, CTV, audio, DOOH. +**Decisioning Platform** +Technical infrastructure that selects which ad to serve at impression time. Receives activated signals and executes campaigns. Examples: DSPs (The Trade Desk), SSPs (Index Exchange, OpenX, PubMatic), ad servers (Google Ad Manager, Kevel). + **DOOH (Digital Out-of-Home)** Digital advertising displayed on screens in public spaces such as billboards, transit stations, airports, and retail locations. Uses CPM or flat_rate pricing with parameters for SOV, duration, and venue targeting. **DSP (Demand-Side Platform)** -Technology platform that allows advertisers to buy advertising inventory programmatically. +A type of decisioning platform that allows advertisers to buy advertising inventory programmatically. ## E @@ -163,11 +166,14 @@ Pricing model based on a percentage of media spend rather than fixed CPM. ## S +**Sales Agent** +An MCP server that exposes publisher inventory for discovery and purchase. Handles product discovery, media buy creation, and campaign management. Examples: Publisher ad servers exposing AdCP interfaces, sales house platforms. + **Screen Time** Total duration an ad was displayed across all DOOH screens, measured in seconds. Used for DOOH delivery reporting. **Seat** -A specific advertising account within a platform, typically representing a brand or campaign. +A specific advertising account within a decisioning platform, typically representing a brand or campaign. **Segment ID** The specific identifier used for signal activation, may differ from signal_id. @@ -175,9 +181,15 @@ The specific identifier used for signal activation, may differ from signal_id. **Share of Voice (SOV)** Percentage of available ad inventory allocated to a specific advertiser in DOOH loops. Expressed as 0.0-1.0 (e.g., 0.15 = 15% SOV). +**Signal Agent** +An MCP server that provides signal discovery and activation services. Enables natural language audience discovery and deploys signals to decisioning platforms. Can be private (owned by a single principal) or marketplace (licensing data to multiple principals). Examples: LiveRamp, Experian, Peer39. + **Size Unit** (Signals Protocol) The measurement type for signal size: individuals, devices, or households. +**SSP (Supply-Side Platform)** +A type of decisioning platform that helps publishers sell advertising inventory programmatically. SSPs connect to multiple demand sources and make ad selection decisions. Examples: Index Exchange, OpenX, PubMatic, Magnite. + ## T **Takeover** diff --git a/v2.6-rc/docs/reference/gmsf-reference.mdx b/dist/docs/2.5.3/reference/gmsf-reference.mdx similarity index 100% rename from v2.6-rc/docs/reference/gmsf-reference.mdx rename to dist/docs/2.5.3/reference/gmsf-reference.mdx diff --git a/v2.6-rc/docs/reference/implementor-faq.mdx b/dist/docs/2.5.3/reference/implementor-faq.mdx similarity index 98% rename from v2.6-rc/docs/reference/implementor-faq.mdx rename to dist/docs/2.5.3/reference/implementor-faq.mdx index 747ada9c0c..ce93b224df 100644 --- a/v2.6-rc/docs/reference/implementor-faq.mdx +++ b/dist/docs/2.5.3/reference/implementor-faq.mdx @@ -289,7 +289,7 @@ assert(response.message.includes("policy")); 3. Verify the sales agent URL appears in `authorized_agents` 4. Reject products from unauthorized agents -See [Authorization Validation](/docs/governance/property/adagents#buyer-agent-validation) for complete requirements. +See [Authorization Validation](/docs/media-buy/capability-discovery/adagents#buyer-agent-validation) for complete requirements. ## Terminology diff --git a/v2.6-rc/docs/reference/media-buy-quick-reference.mdx b/dist/docs/2.5.3/reference/media-buy-quick-reference.mdx similarity index 100% rename from v2.6-rc/docs/reference/media-buy-quick-reference.mdx rename to dist/docs/2.5.3/reference/media-buy-quick-reference.mdx diff --git a/v2.6-rc/docs/reference/release-notes.mdx b/dist/docs/2.5.3/reference/release-notes.mdx similarity index 100% rename from v2.6-rc/docs/reference/release-notes.mdx rename to dist/docs/2.5.3/reference/release-notes.mdx diff --git a/v2.6-rc/docs/reference/roadmap.mdx b/dist/docs/2.5.3/reference/roadmap.mdx similarity index 94% rename from v2.6-rc/docs/reference/roadmap.mdx rename to dist/docs/2.5.3/reference/roadmap.mdx index 137ddeb29e..35b1ec2d61 100644 --- a/v2.6-rc/docs/reference/roadmap.mdx +++ b/dist/docs/2.5.3/reference/roadmap.mdx @@ -59,9 +59,9 @@ These features are in active development but may not make the 3.0 release: The following features are in the working group planning stages: -### Governance Protocol [3.0] +### Governance Protocol -Property governance (property lists, filters, adagents.json authorization), brand standards (brand manifests, creative guidelines), and compliance controls. See the [Governance Protocol](/docs/governance/index) for current specification. +A framework for multi-party approval workflows and delegated authority management. See the [Governance Protocol Working Document](https://docs.google.com/document/d/1osokTr5Xk2PyLBUHbx2jpPad0TLrQIDh2I6ZWzpHMmY/edit?tab=t.0) for details. ### Private Marketplace (PMP) Support - Deal ID integration diff --git a/v2.6-rc/docs/reference/schema-versioning.mdx b/dist/docs/2.5.3/reference/schema-versioning.mdx similarity index 93% rename from v2.6-rc/docs/reference/schema-versioning.mdx rename to dist/docs/2.5.3/reference/schema-versioning.mdx index 7b979d3ffd..8c11d4606e 100644 --- a/v2.6-rc/docs/reference/schema-versioning.mdx +++ b/dist/docs/2.5.3/reference/schema-versioning.mdx @@ -21,7 +21,7 @@ All AdCP schemas are available at multiple paths: ### Exact Version (Recommended for Production) ``` -/schemas/2.6.0/core/product.json +/schemas/2.5.0/core/product.json ``` - **Pin to specific release** - URL never changes - **Guaranteed stability** - Schema won't update unexpectedly @@ -69,8 +69,8 @@ Bundled schemas are experimental and may change or be removed in future releases For tools that don't support `$ref` resolution (some API clients, code generators, or desktop applications), AdCP provides **bundled schemas** with all references resolved inline: ``` -/schemas/2.6.0/bundled/media-buy/create-media-buy-request.json -/schemas/2.6.0/bundled/media-buy/get-products-response.json +/schemas/2.5.0/bundled/media-buy/create-media-buy-request.json +/schemas/2.5.0/bundled/media-buy/get-products-response.json ``` ### What's Bundled @@ -91,11 +91,11 @@ Bundled schemas are generated for all request/response schemas (`*-request.json` ```javascript // Bundled - self-contained, no ref resolution needed -const schema = await fetch('https://adcp.org/schemas/2.6.0/bundled/media-buy/create-media-buy-request.json'); +const schema = await fetch('https://adcp.org/schemas/2.5.0/bundled/media-buy/create-media-buy-request.json'); const validate = ajv.compile(await schema.json()); // Modular - requires $ref resolution -const schema = await fetch('https://adcp.org/schemas/2.6.0/media-buy/create-media-buy-request.json'); +const schema = await fetch('https://adcp.org/schemas/2.5.0/media-buy/create-media-buy-request.json'); // This schema contains $ref to other schemas that must be resolved ``` @@ -105,7 +105,7 @@ Bundled schemas include a `_bundled` field with generation metadata: ```json { - "$id": "/schemas/2.6.0/bundled/core/product.json", + "$id": "/schemas/2.5.0/bundled/core/product.json", "title": "Product", "_bundled": { "generatedAt": "2024-12-17T10:30:00.000Z", @@ -120,7 +120,7 @@ Bundled schemas include a `_bundled` field with generation metadata: ```javascript // Production - pin exact version -const SCHEMA_VERSION = '2.6.0'; +const SCHEMA_VERSION = '2.5.0'; const schema = await fetch(`https://adcp.org/schemas/${SCHEMA_VERSION}/core/product.json`); // Stable development - track minor version (patch updates only) @@ -137,12 +137,12 @@ Always use exact versions to ensure generated types match your target protocol v ```bash # TypeScript SDK generation npx json-schema-to-typescript \ - https://adcp.org/schemas/2.6.0/core/product.json \ + https://adcp.org/schemas/2.5.0/core/product.json \ --output types/product.d.ts # Python SDK generation datamodel-codegen \ - --url https://adcp.org/schemas/2.6.0/core/product.json \ + --url https://adcp.org/schemas/2.5.0/core/product.json \ --output models/product.py ``` @@ -153,7 +153,7 @@ datamodel-codegen \ import Ajv from 'ajv'; const ajv = new Ajv(); -const schema = await fetch('https://adcp.org/schemas/2.6.0/core/product.json'); +const schema = await fetch('https://adcp.org/schemas/2.5.0/core/product.json'); const validate = ajv.compile(await schema.json()); if (!validate(data)) { @@ -227,7 +227,7 @@ If you're currently using `/schemas/v2/`: ``` 3. **Consider pinning** for production stability: ```javascript - const schema = await fetch('/schemas/2.6.0/core/product.json'); + const schema = await fetch('/schemas/2.5.0/core/product.json'); ``` ### From Exact Version to Major Alias @@ -270,11 +270,11 @@ If you want to track the latest 2.x: ```bash # Get schema registry with version info curl https://adcp.org/schemas/v2/index.json | jq '.adcp_version' -# Output: "2.6.0" +# Output: "2.5.0" # Get version from specific release -curl https://adcp.org/schemas/2.6.0/index.json | jq '.adcp_version' -# Output: "2.6.0" +curl https://adcp.org/schemas/2.5.0/index.json | jq '.adcp_version' +# Output: "2.5.0" ``` ### List Available Versions diff --git a/v2.6-rc/docs/reference/security.mdx b/dist/docs/2.5.3/reference/security.mdx similarity index 89% rename from v2.6-rc/docs/reference/security.mdx rename to dist/docs/2.5.3/reference/security.mdx index 44d946041f..74b01e63de 100644 --- a/v2.6-rc/docs/reference/security.mdx +++ b/dist/docs/2.5.3/reference/security.mdx @@ -21,24 +21,84 @@ AdCP operates in a high-stakes environment where: This document provides security requirements and best practices for AdCP implementations. +## Threat Model + +Understanding the specific threats that AdCP implementations face helps choose appropriate mitigations. Different authentication mechanisms address different threats. + +### Threat Categories + +| Threat | Description | Primary Mitigations | +|--------|-------------|---------------------| +| **Credential Theft** | Attacker obtains valid tokens through phishing, malware, or database breach | Short token expiry, credential rotation, anomaly detection | +| **Token Replay** | Attacker intercepts and reuses a valid token | Short expiry, request signing, one-time-use tokens | +| **Domain Hijacking** | Attacker takes control of a domain (expiry, DNS hijack, BGP hijack) and receives tokens intended for legitimate server | Certificate pinning, domain monitoring, out-of-band verification | +| **Man-in-the-Middle** | Attacker intercepts traffic between client and server | TLS, certificate pinning, mTLS | +| **Privilege Escalation** | Authenticated principal accesses another principal's data | Principal isolation, row-level security, authorization checks | +| **Budget Fraud** | Attacker creates unauthorized financial commitments | Approval workflows, spending limits, anomaly detection | + +### Domain Trust Assumption + +AdCP, like most APIs, operates on the assumption that the domain you're connecting to is controlled by the intended party. This is the **domain trust assumption**. + + +**Critical**: OAuth 2.0 does not protect against domain hijacking. If an attacker controls `api.adplatform.com`, they can complete OAuth authorization flows just as easily as they can accept bearer tokens. The client trusts the domain, regardless of authentication mechanism. + + +**What OAuth provides:** +- Delegated access (user authorizes agent to act on their behalf) +- Scoped permissions (limit what the token can do) +- Token revocation without rotating credentials +- Separation of authentication from authorization + +**What OAuth does NOT provide:** +- Protection against compromised domains +- Verification that the server is the intended recipient +- Protection against man-in-the-middle attacks (beyond what TLS provides) + +**Mitigations for domain trust threats:** + +| Mitigation | How It Helps | +|------------|--------------| +| **TLS Certificate Pinning** | Rejects connections even if attacker has valid cert for the domain | +| **DNSSEC** | Protects against DNS spoofing | +| **Domain Monitoring** | Alerts when domain registration changes or expires | +| **Out-of-Band Verification** | Verify platform identity through secondary channel before large commitments | +| **ads.txt/sellers.json** | Industry-standard publisher authorization verification | + +### Authentication Mechanism Selection + +Choose authentication based on the threats you need to address: + +| Scenario | Recommended Auth | Rationale | +|----------|------------------|-----------| +| Server-to-server integration | API keys with IP allowlist | Simple, server identity verified by IP | +| Agent acting on user's behalf | OAuth 2.0 with PKCE | User controls delegation, scoped permissions | +| High-value financial operations | Request signing + short-lived tokens | Integrity verification beyond auth | +| Zero-trust environment | mTLS | Cryptographic verification of both parties | + ## Risk Classification AdCP operations fall into three risk categories based on their potential impact: ### High-Risk Operations (Financial) -These operations commit real advertising budgets and require the strongest authentication: +These operations commit real advertising budgets and require strong controls: -| Operation | Risk | Recommended Auth | -|-----------|------|------------------| -| `create_media_buy` | Creates financial commitments | OAuth 2.0 or mTLS | -| `update_media_buy` | Modifies budgets and campaign parameters | OAuth 2.0 or mTLS | +| Operation | Risk | Primary Threat | +|-----------|------|----------------| +| `create_media_buy` | Creates financial commitments | Budget fraud, credential theft | +| `update_media_buy` | Modifies budgets and campaign parameters | Unauthorized modifications | **Requirements for High-Risk Operations**: -- Implementations SHOULD use OAuth 2.0 with proper token validation or mutual TLS -- Bearer tokens alone provide weaker security guarantees (see [Bearer Token Risks](#bearer-token-risks)) -- Multi-factor authentication or approval workflows recommended for large budgets -- All requests must be logged with full audit trail +- Short-lived credentials (tokens expiring in ≤15 minutes) +- Request signing for transaction integrity (see [Request Signing](#request-signing-for-financial-operations)) +- Multi-factor authentication or approval workflows for large budgets +- Spending limits and anomaly detection +- Full audit trail with immutable logging + + +**Authentication mechanism alone does not determine security level.** A properly implemented bearer token system with short expiry, request signing, and spending limits provides stronger protection than a long-lived OAuth token without additional controls. + ### Medium-Risk Operations (Data Access) @@ -196,30 +256,38 @@ function verifyWebhookSignature( ### Bearer Token Risks -While bearer tokens (including JWT) are widely used across the industry, they carry specific risks that implementations should understand, particularly for [high-risk financial operations](#high-risk-operations-financial): +Bearer tokens are the industry standard for API authentication (Google Ads, Meta Marketing API, The Trade Desk, etc.). Understanding their specific risks helps implement appropriate mitigations. See [Threat Model](#threat-model) for context. + +**Inherent Risks of Bearer Tokens**: -**Token Interception Risks**: -- **Domain Hijacking**: If a domain expires or is compromised, attackers could receive valid bearer tokens intended for legitimate endpoints. Unlike OAuth flows, there's no bilateral verification that the server is the intended recipient. -- **Man-in-the-Middle**: Without certificate pinning, compromised certificate authorities could enable token interception even over HTTPS. -- **Token Replay**: Stolen tokens can be replayed until expiration. +| Risk | Description | Impact | +|------|-------------|--------| +| **Token Replay** | Stolen tokens can be reused until expiration | Unauthorized access for token lifetime | +| **Credential Theft** | Tokens extracted from logs, memory, or storage | Full account access until detected | +| **No Request Binding** | Token authorizes any request, not specific operations | Attacker can perform any authorized action | -**Mitigations for Bearer Token Usage**: +**Mitigations**: -| Risk | Mitigation | -|------|------------| -| Domain hijacking | Certificate pinning, domain monitoring, short token expiry | -| Token interception | mTLS, OAuth 2.0 with PKCE, token binding | -| Token replay | Short expiration (15 min), one-time-use tokens, request signing | -| Credential theft | Hardware security modules, secure enclaves | +| Risk | Mitigation | Implementation | +|------|------------|----------------| +| Token replay | Short expiration | ≤15 minute token lifetime | +| Token replay | Request signing | HMAC signature on payload + timestamp | +| Credential theft | Secure storage | HSM, secure enclaves, encrypted at rest | +| Credential theft | Anomaly detection | Alert on unusual access patterns | +| No request binding | Request signing | Signature covers specific operation parameters | + + +**Common Misconception**: OAuth 2.0 does not protect against domain hijacking. See [Domain Trust Assumption](#domain-trust-assumption) for why switching to OAuth doesn't address this threat. + -**When to Use Stronger Authentication**: +**When to Add Request Signing**: -For high-risk operations (`create_media_buy`, `update_media_buy`), consider: -- **OAuth 2.0 with PKCE**: Provides bilateral verification through the authorization flow -- **Mutual TLS (mTLS)**: Cryptographically verifies both client and server identity -- **Request Signing**: HMAC or asymmetric signatures on request payloads +For financial operations, request signing provides transaction integrity regardless of authentication mechanism: +- Proves the request wasn't modified in transit +- Binds the token to specific operation parameters +- Provides non-repudiation for audit purposes -**Example: Request Signing for Financial Operations**: +### Request Signing for Financial Operations ```typescript // Additional security layer for high-value transactions interface SignedRequest { diff --git a/v2.6-rc/docs/reference/signals-quick-reference.mdx b/dist/docs/2.5.3/reference/signals-quick-reference.mdx similarity index 100% rename from v2.6-rc/docs/reference/signals-quick-reference.mdx rename to dist/docs/2.5.3/reference/signals-quick-reference.mdx diff --git a/v2.6-rc/docs/signals/overview.mdx b/dist/docs/2.5.3/signals/overview.mdx similarity index 100% rename from v2.6-rc/docs/signals/overview.mdx rename to dist/docs/2.5.3/signals/overview.mdx diff --git a/v2.6-rc/docs/signals/specification.mdx b/dist/docs/2.5.3/signals/specification.mdx similarity index 96% rename from v2.6-rc/docs/signals/specification.mdx rename to dist/docs/2.5.3/signals/specification.mdx index 2e511a628e..7ea619d577 100644 --- a/v2.6-rc/docs/signals/specification.mdx +++ b/dist/docs/2.5.3/signals/specification.mdx @@ -35,10 +35,10 @@ The Signals Activation Protocol operates within the broader [AdCP Ecosystem Laye Every signal discovery request involves two key roles: #### Orchestrator -The platform or system making the API request to the signal platform: +The platform or system making the API request to the signal agent: - **Examples**: Scope3, Claude AI assistant, trading desk platform, campaign management tool - **Responsibilities**: Makes API calls, handles authentication, manages the technical interaction -- **Account**: Has technical credentials and API access to the signal platform +- **Account**: Has technical credentials and API access to the signal agent #### Principal The entity on whose behalf the request is being made: @@ -48,7 +48,7 @@ The entity on whose behalf the request is being made: #### How This Works in Practice -1. **Request Flow**: Orchestrator → Signal Platform (on behalf of Principal) → Decisioning Platform +1. **Request Flow**: Orchestrator → Signal Agent (on behalf of Principal) → Decisioning Platform 2. **Authentication**: Orchestrator authenticates with technical credentials 3. **Authorization**: Principal's identity determines available signals and pricing 4. **Activation**: Signals are activated for Principal's account on the decisioning platform @@ -95,7 +95,7 @@ The entity on whose behalf the request is being made: #### Private Signal Agents Agents owned by the principal with exclusive access: -- **Examples**: Walmart's internal signal platform, retailer first-party data, weather APIs, location providers +- **Examples**: Walmart's internal data systems, retailer first-party data, weather APIs, location providers - **Business Model**: No signal costs (workflow orchestration only) - **Access**: Only visible and accessible to the owning principal - **Discovery**: Not discoverable by other principals @@ -146,9 +146,9 @@ The identifier assigned by the decisioning platform after activation: - **Timing**: Only available after successful activation - **Variability**: May differ by platform and account for the same signal -### Agent vs Data Provider +### Signal Agent vs Data Provider -- **Agent**: The signal platform facilitating access (e.g., LiveRamp, Experian) +- **Signal Agent**: The MCP server facilitating signal access (e.g., LiveRamp, Experian) - **Data Provider**: The original source of the signal data (e.g., Polk, Acxiom, Peer39, weather services, location providers) A signal agent may host segments from multiple data providers in their marketplace. @@ -268,14 +268,14 @@ Some operations (like signal activation) are asynchronous and include: Each MCP session involves two levels of identification: #### Orchestrator Authentication -The technical credentials used by the orchestrator to authenticate with the signal platform: +The technical credentials used by the orchestrator to authenticate with the signal agent: - **API Keys**: Technical access credentials for the orchestrator platform - **Session Scope**: Determines what operations the orchestrator can perform -- **Platform Permissions**: What signal platforms the orchestrator can access +- **Agent Permissions**: What signal agents the orchestrator can access -#### Principal Authorization +#### Principal Authorization The principal's identity determines business-level access and pricing: -- **Account Relationship**: Whether the principal has a direct relationship with the signal platform +- **Account Relationship**: Whether the principal has a direct relationship with the signal agent - **Pricing Tier**: Negotiated rates, marketplace rates, or enterprise discounts - **Signal Access**: Private signals, premium segments, or marketplace-only access - **Billing Account**: Where usage charges are applied diff --git a/v2.6-rc/docs/signals/tasks/activate_signal.mdx b/dist/docs/2.5.3/signals/tasks/activate_signal.mdx similarity index 100% rename from v2.6-rc/docs/signals/tasks/activate_signal.mdx rename to dist/docs/2.5.3/signals/tasks/activate_signal.mdx diff --git a/v2.6-rc/docs/signals/tasks/get_signals.mdx b/dist/docs/2.5.3/signals/tasks/get_signals.mdx similarity index 100% rename from v2.6-rc/docs/signals/tasks/get_signals.mdx rename to dist/docs/2.5.3/signals/tasks/get_signals.mdx diff --git a/v2.6-rc/docs/spec-guidelines.md b/dist/docs/2.5.3/spec-guidelines.md similarity index 100% rename from v2.6-rc/docs/spec-guidelines.md rename to dist/docs/2.5.3/spec-guidelines.md diff --git a/docs.json b/docs.json index 5718a9e514..5c3a77b754 100644 --- a/docs.json +++ b/docs.json @@ -52,7 +52,7 @@ "navigation": { "versions": [ { - "version": "2.5", + "version": "2.6", "groups": [ { "group": "Getting Started", @@ -80,6 +80,13 @@ "docs/protocols/envelope-examples" ] }, + { + "group": "adagents.json", + "pages": [ + "docs/media-buy/capability-discovery/adagents", + "docs/media-buy/capability-discovery/authorized-properties" + ] + }, { "group": "Signals Protocol", "pages": [ @@ -94,57 +101,6 @@ } ] }, - { - "group": "Governance Protocol [3.0]", - "pages": [ - "docs/governance/index", - { - "group": "Property Governance", - "pages": [ - "docs/governance/property/index", - "docs/governance/property/specification", - "docs/governance/property/authorized-properties", - "docs/governance/property/adagents", - { - "group": "Tasks", - "pages": [ - "docs/governance/property/tasks/index", - "docs/governance/property/tasks/list_property_features", - "docs/governance/property/tasks/property_lists", - "docs/governance/property/tasks/validate_property_delivery" - ] - } - ] - }, - { - "group": "Brand Standards", - "pages": [ - "docs/governance/brand-standards/index" - ] - }, - { - "group": "Content Standards", - "pages": [ - "docs/governance/content-standards/index", - "docs/governance/content-standards/artifacts", - "docs/governance/content-standards/implementation-guide", - { - "group": "Tasks", - "pages": [ - "docs/governance/content-standards/tasks/list_content_standards", - "docs/governance/content-standards/tasks/get_content_standards", - "docs/governance/content-standards/tasks/create_content_standards", - "docs/governance/content-standards/tasks/update_content_standards", - "docs/governance/content-standards/tasks/delete_content_standards", - "docs/governance/content-standards/tasks/calibrate_content", - "docs/governance/content-standards/tasks/get_media_buy_artifacts", - "docs/governance/content-standards/tasks/validate_content_delivery" - ] - } - ] - } - ] - }, { "group": "Curation Protocol", "pages": [ @@ -248,9 +204,7 @@ { "group": "Reference", "pages": [ - "docs/reference/media-buy-quick-reference", - "docs/reference/signals-quick-reference", - "docs/reference/creative-quick-reference", + "docs/reference/media-channel-taxonomy", "docs/reference/roadmap", "docs/reference/release-notes", "docs/reference/changelog", @@ -272,51 +226,51 @@ ] }, { - "version": "2.6-rc", + "version": "2.5", "groups": [ { "group": "Getting Started", "pages": [ - "v2.6-rc/docs/intro", - "v2.6-rc/docs/quickstart" + "dist/docs/2.5.3/intro", + "dist/docs/2.5.3/quickstart" ] }, { "group": "Protocols", "pages": [ - "v2.6-rc/docs/protocols/getting-started", - "v2.6-rc/docs/protocols/core-concepts", + "dist/docs/2.5.3/protocols/getting-started", + "dist/docs/2.5.3/protocols/core-concepts", { "group": "Choose Your Protocol", "pages": [ - "v2.6-rc/docs/protocols/mcp-guide", - "v2.6-rc/docs/protocols/a2a-guide", - "v2.6-rc/docs/protocols/a2a-response-format" + "dist/docs/2.5.3/protocols/mcp-guide", + "dist/docs/2.5.3/protocols/a2a-guide", + "dist/docs/2.5.3/protocols/a2a-response-format" ] }, - "v2.6-rc/docs/protocols/protocol-comparison", - "v2.6-rc/docs/protocols/context-management", - "v2.6-rc/docs/protocols/task-management", - "v2.6-rc/docs/protocols/envelope-examples" + "dist/docs/2.5.3/protocols/protocol-comparison", + "dist/docs/2.5.3/protocols/context-management", + "dist/docs/2.5.3/protocols/task-management", + "dist/docs/2.5.3/protocols/envelope-examples" ] }, { "group": "adagents.json", "pages": [ - "v2.6-rc/docs/media-buy/capability-discovery/adagents", - "v2.6-rc/docs/media-buy/capability-discovery/authorized-properties" + "dist/docs/2.5.3/media-buy/capability-discovery/adagents", + "dist/docs/2.5.3/media-buy/capability-discovery/authorized-properties" ] }, { "group": "Signals Protocol", "pages": [ - "v2.6-rc/docs/signals/overview", - "v2.6-rc/docs/signals/specification", + "dist/docs/2.5.3/signals/overview", + "dist/docs/2.5.3/signals/specification", { "group": "Tasks", "pages": [ - "v2.6-rc/docs/signals/tasks/get_signals", - "v2.6-rc/docs/signals/tasks/activate_signal" + "dist/docs/2.5.3/signals/tasks/get_signals", + "dist/docs/2.5.3/signals/tasks/activate_signal" ] } ] @@ -324,68 +278,68 @@ { "group": "Curation Protocol", "pages": [ - "v2.6-rc/docs/curation/coming-soon" + "dist/docs/2.5.3/curation/coming-soon" ] }, { "group": "Media Buy Protocol", "pages": [ - "v2.6-rc/docs/media-buy/index", + "dist/docs/2.5.3/media-buy/index", { "group": "Task Reference", "pages": [ - "v2.6-rc/docs/media-buy/task-reference/index", - "v2.6-rc/docs/media-buy/task-reference/get_products", - "v2.6-rc/docs/media-buy/task-reference/list_creative_formats", - "v2.6-rc/docs/media-buy/task-reference/list_authorized_properties", - "v2.6-rc/docs/media-buy/task-reference/create_media_buy", - "v2.6-rc/docs/media-buy/task-reference/list_creatives", - "v2.6-rc/docs/media-buy/task-reference/sync_creatives", - "v2.6-rc/docs/media-buy/task-reference/get_media_buy_delivery", - "v2.6-rc/docs/media-buy/task-reference/update_media_buy", - "v2.6-rc/docs/media-buy/task-reference/provide_performance_feedback" + "dist/docs/2.5.3/media-buy/task-reference/index", + "dist/docs/2.5.3/media-buy/task-reference/get_products", + "dist/docs/2.5.3/media-buy/task-reference/list_creative_formats", + "dist/docs/2.5.3/media-buy/task-reference/list_authorized_properties", + "dist/docs/2.5.3/media-buy/task-reference/create_media_buy", + "dist/docs/2.5.3/media-buy/task-reference/list_creatives", + "dist/docs/2.5.3/media-buy/task-reference/sync_creatives", + "dist/docs/2.5.3/media-buy/task-reference/get_media_buy_delivery", + "dist/docs/2.5.3/media-buy/task-reference/update_media_buy", + "dist/docs/2.5.3/media-buy/task-reference/provide_performance_feedback" ] }, { "group": "Capability Discovery", "pages": [ - "v2.6-rc/docs/media-buy/capability-discovery/index", - "v2.6-rc/docs/media-buy/capability-discovery/implementing-standard-formats" + "dist/docs/2.5.3/media-buy/capability-discovery/index", + "dist/docs/2.5.3/media-buy/capability-discovery/implementing-standard-formats" ] }, { "group": "Product Discovery", "pages": [ - "v2.6-rc/docs/media-buy/product-discovery/index", - "v2.6-rc/docs/media-buy/product-discovery/brief-expectations", - "v2.6-rc/docs/media-buy/product-discovery/example-briefs", - "v2.6-rc/docs/media-buy/product-discovery/media-products" + "dist/docs/2.5.3/media-buy/product-discovery/index", + "dist/docs/2.5.3/media-buy/product-discovery/brief-expectations", + "dist/docs/2.5.3/media-buy/product-discovery/example-briefs", + "dist/docs/2.5.3/media-buy/product-discovery/media-products" ] }, { "group": "Media Buys", "pages": [ - "v2.6-rc/docs/media-buy/media-buys/index", - "v2.6-rc/docs/media-buy/media-buys/optimization-reporting", - "v2.6-rc/docs/media-buy/media-buys/policy-compliance" + "dist/docs/2.5.3/media-buy/media-buys/index", + "dist/docs/2.5.3/media-buy/media-buys/optimization-reporting", + "dist/docs/2.5.3/media-buy/media-buys/policy-compliance" ] }, { "group": "Creatives", "pages": [ - "v2.6-rc/docs/media-buy/creatives/index" + "dist/docs/2.5.3/media-buy/creatives/index" ] }, { "group": "Advanced Topics", "pages": [ - "v2.6-rc/docs/media-buy/advanced-topics/index", - "v2.6-rc/docs/media-buy/advanced-topics/pricing-models", - "v2.6-rc/docs/media-buy/advanced-topics/targeting", - "v2.6-rc/docs/media-buy/advanced-topics/agentic-execution-engine", - "v2.6-rc/docs/media-buy/advanced-topics/principals-and-security", - "v2.6-rc/docs/media-buy/advanced-topics/testing", - "v2.6-rc/docs/media-buy/advanced-topics/orchestrator-design" + "dist/docs/2.5.3/media-buy/advanced-topics/index", + "dist/docs/2.5.3/media-buy/advanced-topics/pricing-models", + "dist/docs/2.5.3/media-buy/advanced-topics/targeting", + "dist/docs/2.5.3/media-buy/advanced-topics/agentic-execution-engine", + "dist/docs/2.5.3/media-buy/advanced-topics/principals-and-security", + "dist/docs/2.5.3/media-buy/advanced-topics/testing", + "dist/docs/2.5.3/media-buy/advanced-topics/orchestrator-design" ] } ] @@ -393,30 +347,30 @@ { "group": "Creative", "pages": [ - "v2.6-rc/docs/creative/index", - "v2.6-rc/docs/creative/formats", - "v2.6-rc/docs/creative/asset-types", - "v2.6-rc/docs/creative/creative-manifests", - "v2.6-rc/docs/creative/brand-manifest", - "v2.6-rc/docs/creative/universal-macros", - "v2.6-rc/docs/creative/implementing-creative-agents", - "v2.6-rc/docs/creative/generative-creative", + "dist/docs/2.5.3/creative/index", + "dist/docs/2.5.3/creative/formats", + "dist/docs/2.5.3/creative/asset-types", + "dist/docs/2.5.3/creative/creative-manifests", + "dist/docs/2.5.3/creative/brand-manifest", + "dist/docs/2.5.3/creative/universal-macros", + "dist/docs/2.5.3/creative/implementing-creative-agents", + "dist/docs/2.5.3/creative/generative-creative", { "group": "Channel Guides", "pages": [ - "v2.6-rc/docs/creative/channels/video", - "v2.6-rc/docs/creative/channels/display", - "v2.6-rc/docs/creative/channels/audio", - "v2.6-rc/docs/creative/channels/dooh", - "v2.6-rc/docs/creative/channels/carousels" + "dist/docs/2.5.3/creative/channels/video", + "dist/docs/2.5.3/creative/channels/display", + "dist/docs/2.5.3/creative/channels/audio", + "dist/docs/2.5.3/creative/channels/dooh", + "dist/docs/2.5.3/creative/channels/carousels" ] }, { "group": "Task Reference", "pages": [ - "v2.6-rc/docs/creative/task-reference/build_creative", - "v2.6-rc/docs/creative/task-reference/preview_creative", - "v2.6-rc/docs/creative/task-reference/list_creative_formats" + "dist/docs/2.5.3/creative/task-reference/build_creative", + "dist/docs/2.5.3/creative/task-reference/preview_creative", + "dist/docs/2.5.3/creative/task-reference/list_creative_formats" ] } ] @@ -424,23 +378,25 @@ { "group": "Reference", "pages": [ - "v2.6-rc/docs/reference/media-channel-taxonomy", - "v2.6-rc/docs/reference/roadmap", - "v2.6-rc/docs/reference/release-notes", - "v2.6-rc/docs/reference/changelog", - "v2.6-rc/docs/reference/schema-versioning", - "v2.6-rc/docs/reference/extensions-and-context", - "v2.6-rc/docs/reference/error-codes", - "v2.6-rc/docs/reference/data-models", - "v2.6-rc/docs/reference/authentication", - "v2.6-rc/docs/reference/security", - "v2.6-rc/docs/reference/glossary" + "dist/docs/2.5.3/reference/media-buy-quick-reference", + "dist/docs/2.5.3/reference/signals-quick-reference", + "dist/docs/2.5.3/reference/creative-quick-reference", + "dist/docs/2.5.3/reference/roadmap", + "dist/docs/2.5.3/reference/release-notes", + "dist/docs/2.5.3/reference/changelog", + "dist/docs/2.5.3/reference/schema-versioning", + "dist/docs/2.5.3/reference/extensions-and-context", + "dist/docs/2.5.3/reference/error-codes", + "dist/docs/2.5.3/reference/data-models", + "dist/docs/2.5.3/reference/authentication", + "dist/docs/2.5.3/reference/security", + "dist/docs/2.5.3/reference/glossary" ] }, { "group": "Community", "pages": [ - "v2.6-rc/docs/community/working-group" + "dist/docs/2.5.3/community/working-group" ] } ] diff --git a/scripts/sync-versioned-docs.sh b/scripts/sync-versioned-docs.sh deleted file mode 100755 index 00737ec6d2..0000000000 --- a/scripts/sync-versioned-docs.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/bin/bash -# -# Sync v2.6-rc docs from 2.6.x branch for local testing -# -# Usage: -# ./scripts/sync-versioned-docs.sh # Sync from remote 2.6.x branch -# ./scripts/sync-versioned-docs.sh --local # Sync from local 2.6.x branch (if checked out) -# - -set -e - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -ROOT_DIR="$(dirname "$SCRIPT_DIR")" - -cd "$ROOT_DIR" - -echo "🔄 Syncing v2.6-rc docs from 2.6.x branch..." - -# Check if --local flag is passed -if [[ "$1" == "--local" ]]; then - # Check if 2.6.x branch exists locally - if ! git show-ref --verify --quiet refs/heads/2.6.x; then - echo "❌ Local branch 2.6.x not found. Fetch it first or use remote sync." - exit 1 - fi - SOURCE_REF="2.6.x" - echo "📂 Using local 2.6.x branch" -else - # Fetch latest from remote - echo "📡 Fetching latest 2.6.x from remote..." - git fetch origin 2.6.x - SOURCE_REF="origin/2.6.x" - echo "📂 Using remote origin/2.6.x branch" -fi - -# Remove existing v2.6-rc/docs -rm -rf v2.6-rc/docs -mkdir -p v2.6-rc - -# Extract docs from 2.6.x branch -echo "📦 Extracting docs folder..." -git archive "$SOURCE_REF" -- docs | tar -x -C v2.6-rc/ - -# Count files synced -FILE_COUNT=$(find v2.6-rc/docs -type f | wc -l | tr -d ' ') - -echo "" -echo "✅ Synced $FILE_COUNT files to v2.6-rc/docs/" -echo "" -echo "To test locally with Mintlify:" -echo " npx mintlify dev" -echo "" -echo "⚠️ Note: v2.6-rc/ is tracked in git. Don't commit local changes" -echo " unless you want to override the automated sync." - diff --git a/v2.6-rc/docs/governance/brand-standards/index.mdx b/v2.6-rc/docs/governance/brand-standards/index.mdx deleted file mode 100644 index 15a738adc0..0000000000 --- a/v2.6-rc/docs/governance/brand-standards/index.mdx +++ /dev/null @@ -1,90 +0,0 @@ ---- -sidebar_position: 1 -title: Brand Standards ---- - - -**AdCP 3.0 Proposal** - This protocol is under development for AdCP 3.0. Feedback welcome via [GitHub Discussions](https://github.com/adcontextprotocol/adcp/discussions). - - -Brand Standards governance enables buyers to declare brand requirements that governance agents use to automatically apply appropriate rules across advertising workflows. - -## Overview - -Brand Standards addresses three concerns: - -| Concern | Description | Mechanism | -|---------|-------------|-----------| -| **Brand Identity** | Who is the advertiser? | Brand manifest declarations | -| **Creative Guidelines** | What can the brand show? | Creative constraints and policies | -| **Audience Constraints** | Who should see the ads? | Industry-specific targeting rules | - -## Brand Manifest - -The brand manifest is the core declaration that buyers provide to governance agents: - -```json -{ - "brand_manifest": { - "brand_name": "ToyBrand", - "industry": "toys", - "target_audience": "children_under_13", - "prohibited_categories": ["gambling", "alcohol", "tobacco"], - "creative_guidelines": { - "max_animation_duration": 15, - "require_accessibility": true - } - } -} -``` - -When governance agents receive a brand manifest, they automatically apply: - -- **Regulatory compliance**: COPPA for children's brands, GDPR consent requirements -- **Content filtering**: Block categories inappropriate for the brand's audience -- **Creative validation**: Enforce brand-specific creative guidelines - -## Integration with Property Governance - -Brand manifests work alongside property lists. When creating a property list, include the brand manifest to get automatic rule application: - -```json -{ - "tool": "create_property_list", - "arguments": { - "name": "ToyBrand Q1 Properties", - "base_properties": [ - { - "selection_type": "publisher_tags", - "publisher_domain": "kidsmedia.com", - "tags": ["kids_family", "educational"] - } - ], - "filters": { - "countries_all": ["US"], - "channels_any": ["display", "video"], - "feature_requirements": [ - { "feature_id": "brand_safety", "min_value": 90, "max_value": 100 } - ] - }, - "brand_manifest": { - "brand_name": "ToyBrand", - "industry": "toys", - "target_audience": "children_under_13" - } - } -} -``` - -The governance agent uses the brand manifest to apply COPPA requirements, filter out non-child-safe properties, and enforce relevant industry rules. - -## Coming Soon - -Detailed specification and task definitions for Brand Standards governance are under development. Key planned features: - -- **Brand manifest validation**: Verify manifest completeness and consistency -- **Industry rule sets**: Pre-defined rules for common industries (toys, alcohol, pharmaceuticals, finance) -- **Creative compliance**: Validate creatives against brand guidelines -- **Audience verification**: Ensure targeting complies with brand audience constraints - -See the [Governance Protocol overview](/docs/governance/index) for the broader context of how Brand Standards fits into AdCP governance. diff --git a/v2.6-rc/docs/governance/content-standards/artifacts.mdx b/v2.6-rc/docs/governance/content-standards/artifacts.mdx deleted file mode 100644 index 7d2f834a2a..0000000000 --- a/v2.6-rc/docs/governance/content-standards/artifacts.mdx +++ /dev/null @@ -1,304 +0,0 @@ ---- -title: Artifacts -sidebar_position: 2 ---- - -# Artifacts - -An **artifact** is a unit of content adjacent to an ad placement. When evaluating brand safety and suitability, you're asking: "Is this artifact appropriate for my brand's ads?" - -## What Is an Artifact? - -Artifacts represent the content context where an ad appears: - -- A **news article** on a website -- A **podcast segment** between ad breaks -- A **video chapter** in a YouTube video -- A **social media post** in a feed -- A **scene** in a CTV show -- An **AI-generated image** in a chat conversation - -Artifacts are identified by `property_id` + `artifact_id` - the property defines where the content lives, and the artifact_id is an opaque identifier for that specific piece of content. The artifact_id scheme is flexible - it could be a URL path, a platform-specific ID, or any consistent identifier the property owner uses internally. - -## Structure - -**Schema**: [artifact.json](https://adcontextprotocol.org/schemas/v2/content-standards/artifact.json) - -```json -{ - "property_id": {"type": "domain", "value": "reddit.com"}, - "artifact_id": "r_fitness_post_abc123", - "assets": [ - {"type": "text", "role": "title", "content": "Best protein sources for muscle building", "language": "en"}, - {"type": "text", "role": "paragraph", "content": "Looking for recommendations on high-quality protein sources...", "language": "en"}, - {"type": "image", "url": "https://cdn.reddit.com/fitness-image.jpg", "alt_text": "Person lifting weights"} - ] -} -``` - -### Required Fields - -| Field | Description | -|-------|-------------| -| `property_id` | Where this artifact lives - uses standard identifier types (`domain`, `app_id`, `apple_podcast_id`, etc.) | -| `artifact_id` | Unique identifier within the property - the property owner defines their scheme | -| `assets` | Content in document order - text blocks, images, video, audio | - -### Optional Fields - -| Field | Description | -|-------|-------------| -| `variant_id` | Identifies a specific variant (A/B test, translation, temporal version) | -| `format_id` | Reference to format registry (same as creative formats) | -| `url` | Web URL if the artifact has one | -| `metadata` | Artifact-level metadata (Open Graph, JSON-LD, author info) | -| `published_time` | When the artifact was published | -| `last_update_time` | When the artifact was last modified | - -## Variants - -The same artifact may have multiple variants: - -- **Translations** - English version vs Spanish version -- **A/B tests** - Different headlines being tested -- **Temporal versions** - Content that changed on Wednesday - -Use `variant_id` to distinguish between them: - -```json -// English version -{ - "property_id": {"type": "domain", "value": "nytimes.com"}, - "artifact_id": "article_12345", - "variant_id": "en", - "assets": [ - {"type": "text", "role": "title", "content": "Breaking News Story", "language": "en"} - ] -} - -// Spanish translation -{ - "property_id": {"type": "domain", "value": "nytimes.com"}, - "artifact_id": "article_12345", - "variant_id": "es", - "assets": [ - {"type": "text", "role": "title", "content": "Noticia de última hora", "language": "es"} - ] -} - -// A/B test variant -{ - "property_id": {"type": "domain", "value": "nytimes.com"}, - "artifact_id": "article_12345", - "variant_id": "headline_test_b", - "assets": [ - {"type": "text", "role": "title", "content": "Alternative Headline Being Tested", "language": "en"} - ] -} -``` - -The combination of `artifact_id` + `variant_id` must be unique within a property. This lets you track which variant a user saw and correlate it with delivery reports. - -## Asset Types - -Assets are the actual content within an artifact. Everything is an asset - titles, paragraphs, images, videos. - -### Text - -```json -{"type": "text", "role": "title", "content": "Article Title", "language": "en"} -{"type": "text", "role": "paragraph", "content": "The article body text...", "language": "en"} -{"type": "text", "role": "description", "content": "A summary of the article", "language": "en"} -{"type": "text", "role": "heading", "content": "Section Header", "heading_level": 2} -{"type": "text", "role": "quote", "content": "A quoted statement"} -``` - -Roles: `title`, `description`, `paragraph`, `heading`, `caption`, `quote`, `list_item` - -Each text asset can have its own `language` tag for mixed-language content. - -### Image - -```json -{ - "type": "image", - "url": "https://cdn.example.com/photo.jpg", - "alt_text": "Description of the image" -} -``` - -### Video - -```json -{ - "type": "video", - "url": "https://cdn.example.com/video.mp4", - "transcript": "Full transcript of the video content...", - "duration_ms": 180000 -} -``` - -### Audio - -```json -{ - "type": "audio", - "url": "https://cdn.example.com/podcast.mp3", - "transcript": "Today we're discussing...", - "duration_ms": 3600000 -} -``` - -## Metadata - -Artifact-level metadata describes the artifact as a whole, not individual assets: - -```json -{ - "metadata": { - "author": "Jane Smith", - "canonical": "https://example.com/article/12345", - "open_graph": { - "og:type": "article", - "og:site_name": "Example News" - }, - "json_ld": [ - { - "@type": "NewsArticle", - "datePublished": "2025-01-15" - } - ] - } -} -``` - -This is separate from assets because it's about the artifact container, not the content itself. - -## Secured Asset Access - -Many assets aren't publicly accessible - AI-generated images, private conversations, paywalled content. The artifact schema supports authenticated access. - -### Pre-Configuration (Recommended) - -For ongoing partnerships, configure access once during onboarding rather than per-request: - -1. **Service account sharing** - Grant the verification agent access to your cloud storage -2. **OAuth client credentials** - Set up machine-to-machine authentication -3. **API key exchange** - Share long-lived API keys during setup - -This happens during the activation phase when the seller first receives content standards from a buyer. - -### Per-Asset Authentication - -When pre-configuration isn't possible, include access credentials with individual assets: - -```json -{ - "type": "image", - "url": "https://cdn.openai.com/secured/img_abc123.png", - "access": { - "method": "bearer_token", - "token": "eyJhbGciOiJIUzI1NiIs..." - } -} -``` - -**Note on token size**: For artifacts with many assets, per-asset tokens can significantly increase payload size. Consider: - -1. **Pre-configured access** - Set up service account access once during onboarding -2. **Shared token reference** - Define tokens at the artifact level and reference by ID -3. **Signed URLs** - Use pre-signed URLs where the URL itself is the credential - -The `url` field is the access URL - it may differ from the artifact's canonical/published URL. For example, a published article at `https://news.example.com/article/123` might have assets served from `https://cdn.example.com/secured/...`. - -### Access Methods - -| Method | Use Case | -|--------|----------| -| `bearer_token` | OAuth2 bearer token in Authorization header | -| `service_account` | GCP/AWS service account credentials | -| `signed_url` | Pre-signed URL with embedded credentials (URL itself is the credential) | - -### Service Account Setup - -For GCP: - -```json -{ - "access": { - "method": "service_account", - "provider": "gcp", - "credentials": { - "type": "service_account", - "project_id": "my-project", - "private_key_id": "...", - "private_key": "-----BEGIN PRIVATE KEY-----\n...", - "client_email": "verification-agent@my-project.iam.gserviceaccount.com" - } - } -} -``` - -For AWS: - -```json -{ - "access": { - "method": "service_account", - "provider": "aws", - "credentials": { - "access_key_id": "AKIAIOSFODNN7EXAMPLE", - "secret_access_key": "...", - "region": "us-east-1" - } - } -} -``` - -### Pre-Signed URLs - -For one-off access without sharing credentials: - -```json -{ - "type": "video", - "url": "https://storage.googleapis.com/bucket/video.mp4?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=...&X-Goog-Signature=...", - "access": { - "method": "signed_url" - } -} -``` - -The URL itself contains the credentials - no additional authentication needed. - -## Property Identifier Types - -The `property_id` uses standard identifier types from the AdCP property schema: - -| Type | Example | Use Case | -|------|---------|----------| -| `domain` | `reddit.com` | Websites | -| `app_id` | `com.spotify.music` | Mobile apps | -| `apple_podcast_id` | `1234567890` | Apple Podcasts | -| `spotify_show_id` | `4rOoJ6Egrf8K2IrywzwOMk` | Spotify podcasts | -| `youtube_channel_id` | `UCddiUEpeqJcYeBxX1IVBKvQ` | YouTube channels | -| `rss_url` | `https://feeds.example.com/podcast.xml` | RSS feeds | - -## Artifact ID Schemes - -The property owner defines their artifact_id scheme. Examples: - -| Property Type | Artifact ID Pattern | Example | -|---------------|---------------------|---------| -| News website | `article_{id}` | `article_12345` | -| Reddit | `r_{subreddit}_{post_id}` | `r_fitness_abc123` | -| Podcast | `episode_{num}_segment_{num}` | `episode_42_segment_2` | -| CTV | `show_{id}_s{season}e{episode}_scene_{num}` | `show_abc_s3e5_scene_12` | -| Social feed | `post_{id}` | `post_xyz789` | - -The verification agent doesn't need to understand the scheme - it's opaque. The property owner uses it to correlate artifacts with their content. - -## Related - -- [Content Standards Overview](/docs/governance/content-standards) - How artifacts fit into the content standards workflow -- [calibrate_content](/docs/governance/content-standards/tasks/calibrate_content) - Sending artifacts for calibration diff --git a/v2.6-rc/docs/governance/content-standards/implementation-guide.mdx b/v2.6-rc/docs/governance/content-standards/implementation-guide.mdx deleted file mode 100644 index c8efbcb77c..0000000000 --- a/v2.6-rc/docs/governance/content-standards/implementation-guide.mdx +++ /dev/null @@ -1,381 +0,0 @@ ---- -title: Implementation Guide -description: How to implement the Content Standards Protocol as a sales agent, orchestrator, or governance agent ---- - -This guide covers implementation patterns for the Content Standards Protocol from three perspectives: - -1. **Sales agents** accepting and enforcing brand safety standards -2. **Orchestrators** coordinating content standards across publishers -3. **Governance agents** providing content evaluation services - -## Roles Overview - -Before diving in, understand who does what: - -| Role | Examples | Responsibilities | -|------|----------|-----------------| -| **Orchestrator** | DSP, trading desk, agency platform | Coordinates media buying; passes standards refs to sellers; receives artifacts for validation | -| **Sales Agent** | Publisher ad server, SSP | Accepts standards; calibrates local model; enforces during delivery; pushes artifacts | -| **Governance Agent** | IAS, DoubleVerify, brand safety service | Hosts standards; implements `calibrate_content` and `validate_content_delivery` | - -The typical flow: - -``` -1. Brand sets up standards with governance agent (via orchestrator) -2. Orchestrator sends standards_ref with get_products/create_media_buy -3. Sales agent accepts or rejects based on capability -4. Sales agent calibrates against governance agent -5. Sales agent enforces during delivery -6. Sales agent provides artifacts (push via webhook or pull via get_media_buy_artifacts) -7. Orchestrator forwards artifacts to governance agent for validation -``` - ---- - -## For Sales Agents - -If you're a sales agent (publisher ad server, SSP, or platform), implementing Content Standards means accepting orchestrator policies and enforcing them during delivery. - -### The Core Model - -When an orchestrator includes a `content_standards_ref` in their request, you must: - -1. **Fetch the standards** from the governance agent and evaluate if you can fulfill them -2. **Accept or reject** the buy based on your capabilities -3. **Calibrate** your evaluation model against the governance agent's expectations -4. **Enforce** the standards during delivery -5. **Provide artifacts** to the orchestrator for validation - -If you cannot fulfill the content standards requirements, **reject the buy**. Don't accept a campaign you can't properly enforce. - -### What You Need to Implement - -**1. Accept content standards references on `get_products` and `create_media_buy`** - -Orchestrators pass their standards via reference: - -```json -{ - "content_standards_ref": { - "standards_id": "nike_emea_brand_safety", - "agent_url": "https://brandsafety.ias.com" - } -} -``` - -When you receive this: -- Fetch the standards document from the governance agent at `agent_url` -- Evaluate whether you can enforce these requirements -- If you cannot meet the standards, reject the request -- If you can, accept and store the association with the media buy - -**2. Decide: Can you fulfill this?** - -The standards document contains: -- Policy (natural language description of acceptable/unacceptable content) -- Calibration exemplars (pass/fail examples to interpret edge cases) -- Floor (reference to external baseline safety standards) - -Review these requirements against your capabilities. Different publishers have different definitions of "adjacency" - Reddit might include comments, YouTube might include related videos, a news site might mean the article body. That's fine - as long as you can meaningfully enforce the brand's intent, accept the buy. - -If you can't - for example, they need adjacency data for a channel where it doesn't apply (like billboards) - reject the buy. - -**3. Build your evaluation capability** - -Use the standards document to train or configure your content evaluation system. This could be: -- An LLM with the rules as system prompt -- A classifier trained on the calibration examples -- A rules engine for deterministic evaluation -- A third-party brand safety vendor - -The protocol doesn't prescribe your implementation - just that you honor the standards. - -**4. Calibrate against the governance agent** - -After accepting the buy, calibrate your local model by calling `calibrate_content` on the governance agent. You send sample artifacts from your inventory, they tell you how they would rate them: - -```json -// You send examples from your inventory to the governance agent -{ - "standards_id": "nike_emea_brand_safety", - "artifacts": [ - { - "property_id": { "type": "domain", "value": "espn.com" }, - "artifact_id": "article_123", - "assets": [{ "type": "text", "role": "title", "content": "Marathon Runner Collapses at Finish Line" }] - } - ] -} - -// Governance agent responds with their interpretation -{ - "evaluations": [{ - "artifact_id": "article_123", - "suitable": true, - "confidence": 0.9, - "explanation": "Sports injury coverage in athletic context - aligns with brand's sports marketing positioning" - }] -} -``` - -Use these responses to train your local model. If you disagree with a rating, ask follow-up questions to understand the governance agent's reasoning. - -**5. Push artifacts to the orchestrator** - -After delivery, push artifacts to the orchestrator so they can validate against the governance agent. Configure via `artifact_webhook` in the media buy: - -```json -// Artifact webhook payload (you send this to the orchestrator) -{ - "media_buy_id": "mb_nike_reddit_q1", - "batch_id": "batch_20250115_001", - "timestamp": "2025-01-15T11:00:00Z", - "artifacts": [ - { - "artifact": { - "property_id": { "type": "domain", "value": "reddit.com" }, - "artifact_id": "r_fitness_abc123", - "assets": [{ "type": "text", "role": "title", "content": "Best protein sources" }] - }, - "delivered_at": "2025-01-15T10:30:00Z", - "impression_id": "imp_abc123" - } - ] -} -``` - -Also support `get_media_buy_artifacts` for orchestrators who prefer to poll. - -### Implementation Checklist - -- [ ] Parse `content_standards_ref` in `get_products` and `create_media_buy` -- [ ] Fetch and evaluate standards documents from governance agents -- [ ] Reject buys you cannot fulfill - don't accept campaigns you can't enforce -- [ ] Build content evaluation against the standards document -- [ ] Call `calibrate_content` on the governance agent to align interpretation -- [ ] Implement `get_media_buy_artifacts` so orchestrators can retrieve content for validation -- [ ] Support `artifact_webhook` for push-based artifact delivery -- [ ] Support `reporting_webhook` for delivery metrics - ---- - -## For Orchestrators - -If you're an orchestrator (DSP, trading desk, or agency platform), you coordinate content standards between brands, governance agents, and publishers. - -### The Orchestration Pattern - -``` -Brand → Orchestrator → Governance Agent (setup) - → Sales Agent (buying) - ← Sales Agent (artifacts) - → Governance Agent (validation) - → Brand (reporting) -``` - -**1. Help brands set up standards with governance agents** - -Brands create content standards through a governance agent. You might facilitate this or the brand may do it directly: - -```json -// Standards stored at the governance agent -{ - "standards_id": "nike_emea_brand_safety", - "name": "Nike EMEA Brand Safety Policy", - "brand_id": "nike", - "policy": "Sports and fitness content is ideal. Avoid violence, adult themes, drugs.", - "calibration_exemplars": { - "pass": [ - { "type": "url", "value": "https://espn.com/nba/story/_/id/12345/lakers-win", "language": "en" } - ], - "fail": [ - { "type": "url", "value": "https://tabloid.example.com/celebrity-scandal", "language": "en" } - ] - } -} -``` - -**2. Pass standards references when buying** - -When discovering products or creating media buys, include the governance agent reference: - -```json -{ - "product_id": "espn_sports_display", - "packages": [...], - "content_standards_ref": { - "standards_id": "nike_emea_brand_safety", - "agent_url": "https://brandsafety.ias.com" - }, - "artifact_webhook": { - "url": "https://your-platform.com/webhooks/artifacts", - "authentication": { - "schemes": ["HMAC-SHA256"], - "credentials": "your-shared-secret-min-32-chars" - }, - "delivery_mode": "batched", - "batch_frequency": "hourly", - "sampling_rate": 0.25 - } -} -``` - -If the publisher cannot fulfill the standards, they should reject the buy. Handle rejections gracefully and find alternative inventory. - -**3. Receive artifacts from sales agents** - -Sales agents push artifacts to your `artifact_webhook` endpoint. Forward them to the governance agent for validation: - -```python -# Receive artifact webhook from sales agent -@app.post("/webhooks/artifacts") -async def receive_artifacts(payload: ArtifactWebhookPayload): - # Forward to governance agent for validation - validation_result = await governance_agent.validate_content_delivery( - standards_id=get_standards_id(payload.media_buy_id), - records=[ - {"artifact": a.artifact, "record_id": a.impression_id} - for a in payload.artifacts - ] - ) - - # Log any failures - for result in validation_result.results: - if any(f.status == "failed" for f in result.features): - log_brand_safety_incident(payload.media_buy_id, result) - - return {"status": "received", "batch_id": payload.batch_id} -``` - -**4. Report to brands** - -Surface validation results to the brand: -- **Incidents**: Content that didn't meet standards -- **Coverage**: What percentage of delivery was validated -- **Trends**: Changes in content safety over time - -### Implementation Checklist - -- [ ] Facilitate brand setup with governance agents -- [ ] Include `content_standards_ref` in `get_products` and `create_media_buy` requests -- [ ] Configure `artifact_webhook` to receive artifacts from sales agents -- [ ] Handle rejections from publishers who can't fulfill standards -- [ ] Forward artifacts to governance agent via `validate_content_delivery` -- [ ] Build reporting for brands - ---- - -## For Governance Agents - -If you're a governance agent (IAS, DoubleVerify, or brand safety service), you provide content evaluation as a service. - -### What You Implement - -**1. Host and serve content standards** - -Store standards configurations and expose them via `get_content_standards`: - -```json -// Response to get_content_standards -{ - "standards_id": "nike_emea_brand_safety", - "version": "1.2.0", - "name": "Nike EMEA - all digital channels", - "policy": "Sports and fitness content is ideal. Lifestyle content about health is good...", - "calibration_exemplars": { - "pass": [...], - "fail": [...] - } -} -``` - -**2. Implement `calibrate_content`** - -Sales agents call this to align their local models before campaign execution. They send sample artifacts, you respond with how the brand would rate them: - -```python -def calibrate_content(standards_id: str, artifacts: list) -> dict: - standards = get_standards(standards_id) - evaluations = [] - - for artifact in artifacts: - # Evaluate against brand's policy - result = evaluate_against_policy(artifact, standards) - evaluations.append({ - "artifact_id": artifact["artifact_id"], - "suitable": result.suitable, - "confidence": result.confidence, - "explanation": result.explanation # Help them understand your reasoning - }) - - return {"evaluations": evaluations} -``` - -Calibration is a dialogue - be prepared for follow-up questions and edge cases. - -**3. Implement `validate_content_delivery`** - -Orchestrators call this to validate artifacts after delivery. Batch evaluation at scale: - -```python -def validate_content_delivery(standards_id: str, records: list) -> dict: - standards = get_standards(standards_id) - results = [] - - for record in records: - features = [] - for feature in ["brand_safety", "brand_suitability"]: - evaluation = evaluate_feature(record["artifact"], standards, feature) - features.append({ - "feature_id": feature, - "status": "passed" if evaluation.passed else "failed", - "value": evaluation.value, - "message": evaluation.message if not evaluation.passed else None - }) - results.append({ - "record_id": record["record_id"], - "features": features - }) - - return { - "summary": compute_summary(results), - "results": results - } -``` - -### Implementation Checklist - -- [ ] Implement `create_content_standards` for brands to set up policies -- [ ] Implement `get_content_standards` for sales agents to fetch policies -- [ ] Implement `calibrate_content` for sales agents to align their models -- [ ] Implement `validate_content_delivery` for orchestrators to validate delivery -- [ ] Support dialogue in calibration (follow-up questions, edge cases) - ---- - -## Content Access Pattern - -All three roles may need to exchange content securely. The `content_access` pattern provides authenticated access to a URL namespace: - -```json -{ - "content_access": { - "url_pattern": "https://cache.example.com/*", - "auth": { - "type": "bearer", - "token": "eyJ..." - } - } -} -``` - -- **url_pattern**: URLs matching this pattern use this auth -- **auth.type**: Authentication method (`bearer`, `api_key`, `signed_url`) -- **auth.token**: The credential - -Include this in: -- `get_content_standards` response (governance agent → sales agent: "fetch examples here") -- `get_media_buy_artifacts` response (sales agent → orchestrator: "fetch content here") - -This avoids per-asset tokens and keeps payloads small while enabling secure content exchange. diff --git a/v2.6-rc/docs/governance/content-standards/index.mdx b/v2.6-rc/docs/governance/content-standards/index.mdx deleted file mode 100644 index eda9db83a5..0000000000 --- a/v2.6-rc/docs/governance/content-standards/index.mdx +++ /dev/null @@ -1,358 +0,0 @@ ---- -title: Overview -sidebar_position: 1 ---- - -# Content Standards Protocol - -The Content Standards Protocol enables **privacy-preserving brand safety** for ephemeral and sensitive content that cannot leave a publisher's infrastructure. - -## The Problem - -Traditional brand safety relies on third-party verification: send your content to IAS or DoubleVerify, they evaluate it, return a verdict. This works for static web pages. It fundamentally cannot work for: - -- **AI-generated content** - ChatGPT responses, DALL-E images that exist only in a user session -- **Private conversations** - Content in messaging apps, private social feeds -- **Ephemeral content** - Stories, live streams, real-time feeds that disappear -- **Privacy-regulated content** - GDPR-protected data that cannot be exported - -For these platforms, **there is no traditional verification option**. The content simply cannot leave. OpenAI cannot send user conversations to an external service. A messaging app cannot export private chats. A streaming platform cannot share real-time content before it disappears. - -Yet these are exactly the environments where advertising is growing fastest - and where brands most need safety guarantees. Without a privacy-preserving approach, brands either avoid these channels entirely or accept unknown risk. - -## The Solution: Calibration-Based Alignment - -Content Standards solves this by **using agents to protect privacy**. It's a three-phase model where no sensitive content ever leaves the publisher's infrastructure: - -| Phase | Where It Runs | What Happens | -|-------|---------------|--------------| -| **1. Calibration** | External (safe data only) | Publisher and verification agent align on policy interpretation using synthetic examples or public samples - no PII, no sensitive content | -| **2. Local Execution** | Inside publisher's walls | Publisher runs evaluation on every impression using a local model trained during calibration - content never leaves | -| **3. Validation** | Statistical sampling | Verification agent audits a sample to detect drift - both parties can verify the system is working without exposing PII | - -This inverts the traditional model. Instead of "send us your content, we'll evaluate it," it's "we'll teach you our standards, you evaluate locally, we'll audit statistically." - -**The key insight**: The execution engine runs entirely inside the publisher's infrastructure. For OpenAI, that means brand safety evaluation happens within their firewall - user conversations never leave. For a messaging app, it means private content stays private. The calibration and validation phases provide confidence that the local model is working correctly, without ever requiring access to sensitive data. - -## What It Covers - -- **Brand safety** - Is this content safe for *any* brand? (universal thresholds like hate speech, illegal content) -- **Brand suitability** - Is this content appropriate for *my* brand? (brand-specific preferences and tone) - -## Key Concepts - -Content standards evaluation involves four key questions that buyers and sellers negotiate: - -1. **What content?** - What [artifacts](/docs/governance/content-standards/artifacts) to evaluate (the ad-adjacent content) -2. **How much adjacency?** - How many artifacts around the ad slot to consider -3. **What sampling rate?** - What percentage of traffic to evaluate -4. **How to calibrate?** - How to align on policy interpretation before runtime - -These parameters are negotiated between buyer and seller during product discovery and media buy creation. - -## Workflow - -```mermaid -sequenceDiagram - participant Brand - participant Buyer as Buyer Agent - participant Seller as Seller Agent - participant Verifier as Verification Agent - - Note over Brand,Verifier: 1. SETUP PHASE - Brand->>Verifier: create_content_standards (policy + calibration examples) - Verifier-->>Brand: standards_id - - Note over Brand,Verifier: 2. ACTIVATION PHASE - Brand->>Buyer: "Buy inventory from Reddit, use standards_id X" - Buyer->>Seller: create_media_buy (includes content_standards reference) - - Seller->>Verifier: calibrate_content (sample artifacts) - Verifier-->>Seller: verdict + explanation - Seller->>Verifier: "What about this edge case?" - Verifier-->>Seller: clarification - Note over Seller: Seller builds local model - - Note over Brand,Verifier: 3. RUNTIME PHASE - loop High-volume decisioning - Note over Seller: Local model evaluates artifacts - end - - Buyer->>Seller: get_media_buy_artifacts (sampled) - Seller-->>Buyer: Content artifacts - Buyer->>Verifier: validate_content_delivery - Verifier-->>Buyer: Validation results -``` - -**Key insight**: Runtime decisioning happens locally at the seller (for scale). Buyers pull content samples from sellers and validate against the verification agent. - -## Adjacency - -How much content around the ad slot should be evaluated? - -| Context | Adjacency Examples | -|---------|-------------------| -| **News article** | The article where the ad appears | -| **Social feed** | 1-2 posts above and below the ad slot | -| **Podcast** | The segment before and after the ad break | -| **CTV** | 1-2 scenes before and after the ad pod | -| **Infinite scroll** | Posts within the visible viewport | - -Adjacency requirements are defined by the seller in their product catalog (`get_products`). The buyer can filter products based on adjacency guarantees: - -```json -{ - "product_id": "reddit_feed_standard", - "content_standards_adjacency_definition": { - "before": 2, - "after": 2, - "unit": "posts" - } -} -``` - -### Adjacency Units - -| Unit | Use Case | -|------|----------| -| `posts` | Social feeds, forums, comment threads | -| `scenes` | CTV, streaming video content | -| `segments` | Podcasts, audio content | -| `seconds` | Time-based adjacency in video/audio | -| `viewports` | Infinite scroll contexts | -| `articles` | News sites, content aggregators | - -Different products may offer different adjacency guarantees at different price points. - -## Sampling Rate - -What percentage of traffic should be evaluated by the verification agent? - -| Rate | Use Case | -|------|----------| -| **100%** | Premium brand safety - every impression validated | -| **10-25%** | Standard monitoring - statistical confidence | -| **1-5%** | Spot checking - drift detection only | - -Sampling rate is negotiated in the media buy: - -```json -{ - "governance": { - "content_standards": { - "agent_url": "https://safety.ias.com/adcp", - "standards_id": "nike_brand_safety", - "sampling_rate": 0.25 - } - } -} -``` - -Higher sampling rates typically cost more but provide stronger guarantees. The seller is responsible for implementing the agreed sampling rate and reporting actual coverage. - -## Validation Thresholds - -When a seller calibrates their local model against a verification agent, there's an expected drift - the local model won't match the verification agent 100% of the time. **Validation thresholds** define acceptable drift between local execution and validation samples. - -Sellers advertise their content safety capabilities in their product catalog: - -```json -{ - "product_id": "reddit_feed_premium", - "content_standards": { - "validation_threshold": 0.95, - "validation_threshold_description": "Local model matches verification agent 95% of the time" - } -} -``` - -| Threshold | Meaning | -|-----------|---------| -| **0.99** | Premium - local model is 99% aligned with verification agent | -| **0.95** | Standard - local model is 95% aligned | -| **0.90** | Budget - local model is 90% aligned | - -**This is a contractual guarantee.** If the seller's validation results show more drift than the advertised threshold, buyers can expect remediation (makegoods, refunds, etc.) just like any other delivery discrepancy. - -The threshold answers the key buyer question: "If I accept your local model, how confident can I be that you're enforcing my standards correctly?" - -## Policies - -Content Standards uses **natural language prompts** rather than rigid keyword lists: - -```json -{ - "policy": "Sports and fitness content is ideal. Lifestyle content about health is good. Entertainment is generally acceptable. Avoid content about violence, controversial politics, adult themes, or content portraying sedentary lifestyle positively. Block hate speech, illegal activities, or ongoing litigation against our company.", - "calibration_exemplars": { - "pass": [ - { - "property_id": {"type": "domain", "value": "espn.com"}, - "artifact_id": "nba_championship_recap_2024", - "assets": [{"type": "text", "role": "title", "content": "Championship Game Recap"}] - } - ], - "fail": [ - { - "property_id": {"type": "domain", "value": "tabloid.example.com"}, - "artifact_id": "scandal_story_123", - "assets": [{"type": "text", "role": "title", "content": "Celebrity Scandal Exposed"}] - } - ] - } -} -``` - -The policy prompt enables AI-powered verification agents to understand context and nuance. **Calibration** examples provide a training/test set that helps the agent interpret the policy correctly. - -See [Artifacts](/docs/governance/content-standards/artifacts) for details on artifact structure and secured asset access. - -## Scoped Standards - -Buyers typically maintain multiple standards configurations for different contexts - UK TV campaigns have different regulations than US display, and children's brands need stricter safety than adult beverages. - -```json -{ - "standards_id": "uk_tv_zero_calorie", - "name": "UK TV - zero-calorie brands", - "countries_all": ["GB"], - "channels_any": ["ctv", "linear_tv"] -} -``` - -**The buyer selects the appropriate `standards_id` when creating a media buy.** The seller receives a reference to the resolved standards - they don't need to do scope matching themselves. - -## Calibration - -Before running campaigns, sellers calibrate their local models against the verification agent. This is a **dialogue-based process** that may involve human review on either side: - -1. Seller sends sample artifacts to the verification agent -2. Verification agent returns verdicts with detailed explanations -3. Seller asks follow-up questions about edge cases -4. Process repeats until alignment is achieved - -**Human-in-the-loop**: Calibration often involves humans on both sides. A brand safety specialist at the buyer might review edge cases flagged by the verification agent. A content operations team at the seller might curate calibration samples and validate the local model's learning. The protocol supports async workflows where either party can pause for human review before responding. - -```json -// Seller: "Does this pass?" -{ - "artifact": { - "property_id": {"type": "domain", "value": "reddit.com"}, - "artifact_id": "r_news_politics_123", - "assets": [{"type": "text", "role": "title", "content": "Political News Article"}] - } -} - -// Verification agent: "No, because..." -{ - "verdict": "fail", - "explanation": "Political content is excluded by brand policy, even when balanced.", - "policy_alignment": { - "violations": [{ - "policy_text": "Avoid content about controversial politics", - "violation_reason": "Article discusses ongoing political controversy" - }] - } -} -``` - -See [calibrate_content](/docs/governance/content-standards/tasks/calibrate_content) for the full task specification. - -## Tasks - -### Discovery - -| Task | Description | -|------|-------------| -| [list_content_standards](/docs/governance/content-standards/tasks/list_content_standards) | List available standards configurations | -| [get_content_standards](/docs/governance/content-standards/tasks/get_content_standards) | Retrieve a specific standards configuration | - -### Management - -| Task | Description | -|------|-------------| -| [create_content_standards](/docs/governance/content-standards/tasks/create_content_standards) | Create a new standards configuration | -| [update_content_standards](/docs/governance/content-standards/tasks/update_content_standards) | Update an existing standards configuration | -| [delete_content_standards](/docs/governance/content-standards/tasks/delete_content_standards) | Delete a standards configuration | - -### Calibration & Validation - -| Task | Description | -|------|-------------| -| [calibrate_content](/docs/governance/content-standards/tasks/calibrate_content) | Collaborative dialogue to align on policy interpretation | -| [get_media_buy_artifacts](/docs/governance/content-standards/tasks/get_media_buy_artifacts) | Retrieve content artifacts from a media buy | -| [validate_content_delivery](/docs/governance/content-standards/tasks/validate_content_delivery) | Batch validation of content artifacts | - -## Typical Providers - -- **IAS** - Integral Ad Science -- **DoubleVerify** - Brand safety and verification -- **Scope3** - Sustainability-focused brand safety with prompt-based policies -- **Custom** - Brand-specific implementations - -## Future: Secure Enclaves - -The current model trusts the publisher to faithfully implement the calibrated standards. A future evolution uses **secure enclaves** (Trusted Execution Environments / TEEs) to provide cryptographic guarantees: - -```mermaid -flowchart TB - subgraph VS["Verification Service"] - Models["Models & Calibration Data"] - Results["Aggregate Results"] - end - - subgraph PUB["Publisher Infrastructure"] - subgraph TEE["Secure Enclave (TEE)"] - Agent["Containerized
Governance Agent"] - end - Content["Content Artifacts"] - end - - Models -->|"Pinhole IN:
models, policy, examples"| Agent - Agent -->|"Pinhole OUT:
pass rates, drift metrics"| Results - Content -->|"evaluate"| Agent - Agent -->|"pass/fail verdict"| Content - - style TEE fill:#e8f5e9,stroke:#4caf50 - style Agent fill:#c8e6c9,stroke:#388e3c - style PUB fill:#fafafa,stroke:#9e9e9e -``` - -**Content never crosses the pinhole** - only models flow in, only aggregates flow out. - -### The Pinhole Interface - -The enclave maintains a narrow, well-defined interface to the verification service: - -**Inbound (verification service → enclave):** -- Updated brand safety models -- Policy changes and calibration exemplars -- Configuration updates - -**Outbound (enclave → verification service):** -- Aggregated validation results (pass rates, drift metrics) -- Statistical summaries -- Attestation proofs - -**Never crosses the boundary:** -- Raw content artifacts -- User data or PII -- Individual impression-level data - -This pinhole is the interface that needs standardization - it defines exactly what flows in and out while keeping sensitive content locked inside the publisher's walls. - -### Why This Matters - -- **Publisher** hosts a secure enclave inside their infrastructure -- **Governance agent** (from IAS, DoubleVerify, etc.) runs as a container within the enclave -- **Content** flows into the enclave for evaluation but never leaves the publisher's walls -- **Both parties** can verify the governance code is running unmodified via attestation -- **Models stay current** - the enclave can receive updates without exposing content - -This provides the same privacy guarantees as local execution, but with cryptographic proof that the correct algorithm is running. The brand knows their standards are being enforced faithfully. The publisher proves compliance without exposing content. - -This architecture aligns with the [IAB Tech Lab ARTF (Agentic RTB Framework)](https://iabtechlab.com/standards/artf/), which defines how service providers can package offerings as containers deployed into host infrastructure. ARTF enables hosts to "provide greater access to data and more interaction opportunities to service agents without concerns about leakage, misappropriation or latency" - exactly the model Content Standards requires for privacy-preserving brand safety. - -## Related - -- [Artifacts](/docs/governance/content-standards/artifacts) - What artifacts are and how to structure them -- [Brand Manifest](/docs/creative/brand-manifest) - Static brand identity that can link to standards agents diff --git a/v2.6-rc/docs/governance/content-standards/tasks/calibrate_content.mdx b/v2.6-rc/docs/governance/content-standards/tasks/calibrate_content.mdx deleted file mode 100644 index 801ee3bb53..0000000000 --- a/v2.6-rc/docs/governance/content-standards/tasks/calibrate_content.mdx +++ /dev/null @@ -1,228 +0,0 @@ ---- -title: calibrate_content -sidebar_position: 7 ---- - -# calibrate_content - -Collaborative calibration task for aligning on content standards interpretation. Used during setup to help sellers understand and internalize a buyer's content policies before campaign execution. - -Unlike high-volume runtime evaluation, calibration is a **dialogue-based process** where parties exchange examples and explanations until aligned. - -## When to Use - -- **Seller onboarding**: When a seller first receives content standards from a buyer -- **Policy clarification**: When a seller needs to understand why specific content passes or fails -- **Model training**: When building a local model to run against the standards -- **Drift detection**: Periodic re-calibration to ensure continued alignment - -## Request - -**Schema**: [calibrate-content-request.json](https://adcontextprotocol.org/schemas/v2/content-standards/calibrate-content-request.json) - -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `standards_id` | string | Yes | Standards configuration to calibrate against | -| `artifact` | artifact | Yes | Artifact to evaluate | - -### Artifact - -**Schema**: [artifact.json](https://adcontextprotocol.org/schemas/v2/content-standards/artifact.json) - -An artifact represents content context where ad placements occur - identified by `property_id` + `artifact_id` and represented as a collection of assets: - -```json -{ - "property_id": {"type": "domain", "value": "reddit.com"}, - "artifact_id": "r_fitness_abc123", - "assets": [ - {"type": "text", "role": "title", "content": "Best protein sources for muscle building", "language": "en"}, - {"type": "text", "role": "paragraph", "content": "Looking for recommendations on high-quality protein sources...", "language": "en"}, - {"type": "text", "role": "paragraph", "content": "I've been lifting for 6 months and want to optimize my diet.", "language": "en"}, - {"type": "image", "url": "https://cdn.reddit.com/fitness-image.jpg", "alt_text": "Person lifting weights"} - ] -} -``` - -## Response - -**Schema**: [calibrate-content-response.json](https://adcontextprotocol.org/schemas/v2/content-standards/calibrate-content-response.json) - -### Passing Response - -```json -{ - "verdict": "pass", - "explanation": "This content aligns well with the brand's fitness-focused positioning. Health and fitness content is explicitly marked as 'ideal' in the policy. The discussion is constructive and educational.", - "features": [ - { - "feature_id": "brand_safety", - "status": "passed", - "explanation": "No safety concerns. Content is user-generated but constructive fitness discussion." - }, - { - "feature_id": "brand_suitability", - "status": "passed", - "explanation": "Fitness content matches brand's athletic positioning." - } - ] -} -``` - -### Failing Response with Detailed Explanation - -```json -{ - "verdict": "fail", - "explanation": "This content discusses political topics which the policy explicitly excludes. While the article itself is balanced journalism, the brand has requested to avoid all controversial political content regardless of tone.", - "features": [ - { - "feature_id": "brand_safety", - "status": "passed", - "explanation": "No hate speech, illegal content, or explicit material." - }, - { - "feature_id": "brand_suitability", - "status": "failed", - "explanation": "Political content is excluded by brand policy, even when balanced." - } - ] -} -``` - -### Response Fields - -| Field | Required | Description | -|-------|----------|-------------| -| `verdict` | Yes | Overall `pass` or `fail` decision | -| `explanation` | No | Detailed natural language explanation of the decision | -| `features` | No | Per-feature breakdown with explanations | -| `confidence` | No | Model confidence in the verdict (0-1), when available | - -## Dialogue Flow - -Calibration supports back-and-forth dialogue using the protocol's conversation management. The seller sends content, the verification agent responds with an evaluation and explanation, and the seller can respond with questions or try different content - all within the same conversation context. - -### A2A Example - -```javascript -// Seller sends artifact to evaluate -const response1 = await a2a.send({ - message: { - parts: [{ - kind: "data", - data: { - skill: "calibrate_content", - parameters: { - standards_id: "nike_brand_safety", - artifact: { - property_id: { type: "domain", value: "reddit.com" }, - artifact_id: "r_news_politics_123", - assets: [ - { type: "text", role: "title", content: "Political News Article" } - ] - } - } - } - }] - } -}); -// Response: verdict=fail with feature breakdown - -// Seller asks follow-up question about the decision -const response2 = await a2a.send({ - contextId: response1.contextId, - message: { - parts: [{ - kind: "text", - text: "This is factual news, not opinion. Should balanced journalism be excluded?" - }] - } -}); -// Verification agent clarifies that brand policy excludes ALL political content - -// Seller tries different artifact -const response3 = await a2a.send({ - contextId: response1.contextId, - message: { - parts: [{ - kind: "data", - data: { - skill: "calibrate_content", - parameters: { - standards_id: "nike_brand_safety", - artifact: { - property_id: { type: "domain", value: "reddit.com" }, - artifact_id: "r_running_tips_456", - assets: [ - { type: "text", role: "title", content: "Running Tips" } - ] - } - } - } - }] - } -}); -// Response: verdict=pass - now seller understands the boundaries -``` - -### MCP Example - -```javascript -// Initial calibration request -const response1 = await mcp.call('calibrate_content', { - standards_id: "nike_brand_safety", - artifact: { - property_id: { type: "domain", value: "reddit.com" }, - artifact_id: "r_news_politics_123", - assets: [ - { type: "text", role: "title", content: "Political News Article" } - ] - } -}); -// Response includes context_id for conversation continuity - -// Continue dialogue with follow-up question -const response2 = await mcp.call('calibrate_content', { - context_id: response1.context_id, - standards_id: "nike_brand_safety", - artifact: { - property_id: { type: "domain", value: "reddit.com" }, - artifact_id: "r_news_politics_123", - assets: [ - { type: "text", role: "title", content: "Political News Article" } - ] - } -}); -// Include text message in the protocol envelope asking about balanced journalism - -// Try different artifact in same conversation -const response3 = await mcp.call('calibrate_content', { - context_id: response1.context_id, - standards_id: "nike_brand_safety", - artifact: { - property_id: { type: "domain", value: "reddit.com" }, - artifact_id: "r_running_tips_456", - assets: [ - { type: "text", role: "title", content: "Running Tips" } - ] - } -}); -``` - -The key insight is that the dialogue happens at the **protocol layer**, not the task layer. The verification agent maintains conversation context and can respond to follow-up questions, disagreements, or requests for clarification - just like any agent-to-agent conversation. - -## Calibration vs Runtime - -| Aspect | calibrate_content | Runtime (local model) | -|--------|-------------------|----------------------| -| **Purpose** | Alignment & understanding | High-volume decisioning | -| **Volume** | Low (setup/periodic) | High (every impression) | -| **Response** | Verbose explanations | Pass/fail only | -| **Latency** | Seconds acceptable | Milliseconds required | -| **Dialogue** | Multi-turn conversation | Stateless | - -## Related Tasks - -- [get_content_standards](/docs/governance/content-standards/tasks/get_content_standards) - Retrieve the policies being calibrated against -- [validate_content_delivery](/docs/governance/content-standards/tasks/validate_content_delivery) - Post-campaign delivery validation diff --git a/v2.6-rc/docs/governance/content-standards/tasks/create_content_standards.mdx b/v2.6-rc/docs/governance/content-standards/tasks/create_content_standards.mdx deleted file mode 100644 index 51859ca853..0000000000 --- a/v2.6-rc/docs/governance/content-standards/tasks/create_content_standards.mdx +++ /dev/null @@ -1,90 +0,0 @@ ---- -title: create_content_standards -sidebar_position: 5 ---- - -# create_content_standards - -Create a new content standards configuration. - -**Response time**: < 1s - -## Request - -**Schema**: [create-content-standards-request.json](https://adcontextprotocol.org/schemas/v2/content-standards/create-content-standards-request.json) - -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `scope` | object | Yes | Where this standards configuration applies (must include `languages_any`) | -| `policy` | string | Yes | Natural language policy prompt | -| `calibration_exemplars` | object | No | Training set of pass/fail artifacts for calibration | - -:::note[Brand Safety Floor Requirement] -Implementors MUST apply a brand safety floor regardless of what policy is defined in content standards. Content that violates the floor (hate speech, illegal content, etc.) must be excluded even when no content standards are specified. AdCP does not define the floor specification; this is left to implementors and industry standards (e.g., GARM categories). -::: - -### Example Request - -```json -{ - "scope": { - "countries_all": ["GB", "DE", "FR"], - "channels_any": ["display", "video", "ctv"], - "languages_any": ["en", "de", "fr"], - "description": "EMEA - all digital channels" - }, - "policy": "Sports and fitness content is ideal. Lifestyle content about health and wellness is good. Entertainment content is generally acceptable. Avoid content about violence, controversial political topics, adult themes, or content that portrays sedentary lifestyle positively.", - "calibration_exemplars": { - "pass": [ - { "type": "url", "value": "https://espn.com/nba/story/_/id/12345/lakers-championship", "language": "en" }, - { "type": "url", "value": "https://healthline.com/fitness/cardio-workout", "language": "en" } - ], - "fail": [ - { "type": "url", "value": "https://tabloid.example.com/celebrity-scandal", "language": "en" }, - { "type": "url", "value": "https://news.example.com/controversial-politics-article", "language": "en" } - ] - } -} -``` - -## Response - -**Schema**: [create-content-standards-response.json](https://adcontextprotocol.org/schemas/v2/content-standards/create-content-standards-response.json) - -### Success Response - -```json -{ - "standards_id": "emea_digital_safety" -} -``` - -### Error Responses - -**Scope Conflict:** - -```json -{ - "errors": [ - { - "code": "SCOPE_CONFLICT", - "message": "Standards already exist for country 'DE' on channel 'display'", - "conflicting_standards_id": "emea_digital_safety" - } - ] -} -``` - -## Scope Conflict Handling - -Multiple standards cannot have overlapping scopes for the same country/channel/language combination. When creating standards that would conflict: - -1. **Check existing standards** - Use [list_content_standards](/docs/governance/content-standards/tasks/list_content_standards) filtered by your scope -2. **Update rather than create** - If standards already exist, use [update_content_standards](/docs/governance/content-standards/tasks/update_content_standards) -3. **Narrow the scope** - Adjust countries or channels to avoid overlap - -## Related Tasks - -- [list_content_standards](/docs/governance/content-standards/tasks/list_content_standards) - List all configurations -- [update_content_standards](/docs/governance/content-standards/tasks/update_content_standards) - Update a configuration -- [delete_content_standards](/docs/governance/content-standards/tasks/delete_content_standards) - Delete a configuration diff --git a/v2.6-rc/docs/governance/content-standards/tasks/delete_content_standards.mdx b/v2.6-rc/docs/governance/content-standards/tasks/delete_content_standards.mdx deleted file mode 100644 index 2f38244c51..0000000000 --- a/v2.6-rc/docs/governance/content-standards/tasks/delete_content_standards.mdx +++ /dev/null @@ -1,70 +0,0 @@ ---- -title: delete_content_standards -sidebar_position: 7 ---- - -# delete_content_standards - -Delete a content standards configuration. - -**Response time**: < 500ms - -## Request - -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `standards_id` | string | Yes | ID of the standards configuration to delete | - -### Example Request - -```json -{ - "standards_id": "nike_emea_safety" -} -``` - -## Response - -### Success Response - -```json -{ - "deleted": true, - "standards_id": "nike_emea_safety" -} -``` - -### Error Responses - -**Not Found:** - -```json -{ - "errors": [ - { - "code": "STANDARDS_NOT_FOUND", - "message": "No standards found with ID 'invalid_id'" - } - ] -} -``` - -**Standards In Use:** - -```json -{ - "errors": [ - { - "code": "STANDARDS_IN_USE", - "message": "Cannot delete standards 'nike_emea_safety' - currently referenced by active media buys" - } - ] -} -``` - -Standards cannot be deleted while they are referenced by active media buys. Use [list_content_standards](/docs/governance/content-standards/tasks/list_content_standards) to identify usage, or archive standards by setting an expiration date rather than deleting. - -## Related Tasks - -- [list_content_standards](/docs/governance/content-standards/tasks/list_content_standards) - List all configurations -- [create_content_standards](/docs/governance/content-standards/tasks/create_content_standards) - Create a new configuration diff --git a/v2.6-rc/docs/governance/content-standards/tasks/get_content_standards.mdx b/v2.6-rc/docs/governance/content-standards/tasks/get_content_standards.mdx deleted file mode 100644 index dec5de452e..0000000000 --- a/v2.6-rc/docs/governance/content-standards/tasks/get_content_standards.mdx +++ /dev/null @@ -1,77 +0,0 @@ ---- -title: get_content_standards -sidebar_position: 2 ---- - -# get_content_standards - -Retrieve content safety policies for a specific standards configuration. - -## Request - -**Schema**: [get-content-standards-request.json](https://adcontextprotocol.org/schemas/v2/content-standards/get-content-standards-request.json) - -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `standards_id` | string | Yes | Identifier for the standards configuration | - -## Response - -**Schema**: [get-content-standards-response.json](https://adcontextprotocol.org/schemas/v2/content-standards/get-content-standards-response.json) - -### Success Response - -```json -{ - "standards_id": "emea_digital_safety", - "name": "EMEA - all digital channels", - "countries_all": ["GB", "DE", "FR"], - "channels_any": ["display", "video", "ctv"], - "languages_any": ["en", "de", "fr"], - "policy": "Sports and fitness content is ideal. Lifestyle content about health and wellness is good. Entertainment content is generally acceptable. Avoid content about violence, controversial political topics, adult themes, or content that portrays sedentary lifestyle positively. Block hate speech, illegal activities, or content disparaging athletes.", - "calibration_exemplars": { - "pass": [ - { "type": "url", "value": "https://espn.com/nba/story/_/id/12345/lakers-championship", "language": "en" }, - { "type": "url", "value": "https://healthline.com/fitness/cardio-workout", "language": "en" } - ], - "fail": [ - { "type": "url", "value": "https://tabloid.example.com/celebrity-scandal", "language": "en" }, - { "type": "url", "value": "https://news.example.com/controversial-politics-article", "language": "en" } - ] - } -} -``` - -### Fields - -| Field | Description | -|-------|-------------| -| `standards_id` | Unique identifier for this standards configuration | -| `name` | Human-readable name | -| `countries_all` | ISO country codes - standards apply in ALL listed countries | -| `channels_any` | Ad channels - standards apply to ANY of the listed channels | -| `languages_any` | BCP 47 language tags - standards apply to content in ANY of these languages | -| `policy` | Natural language policy describing acceptable and unacceptable content contexts | -| `calibration_exemplars` | Training/test set of content contexts (pass/fail) to calibrate policy interpretation | - -:::note[Brand Safety Floor Requirement] -Implementors MUST apply a brand safety floor regardless of what policy is defined. AdCP does not define the floor specification. -::: - -### Error Response - -```json -{ - "errors": [ - { - "code": "STANDARDS_NOT_FOUND", - "message": "No standards found with ID 'invalid_id'" - } - ] -} -``` - -## Related Tasks - -- [calibrate_content](/docs/governance/content-standards/tasks/calibrate_content) - Collaborative calibration against these standards -- [list_content_standards](/docs/governance/content-standards/tasks/list_content_standards) - List available standards configurations diff --git a/v2.6-rc/docs/governance/content-standards/tasks/get_media_buy_artifacts.mdx b/v2.6-rc/docs/governance/content-standards/tasks/get_media_buy_artifacts.mdx deleted file mode 100644 index 7b430da991..0000000000 --- a/v2.6-rc/docs/governance/content-standards/tasks/get_media_buy_artifacts.mdx +++ /dev/null @@ -1,205 +0,0 @@ ---- -title: get_media_buy_artifacts -sidebar_position: 8 ---- - -# get_media_buy_artifacts - -Retrieve content artifacts from a media buy for validation. This is separate from `get_media_buy_delivery` which returns performance metrics - artifacts contain the actual content (text, images, video) where ads were placed. - -**Response time**: < 5s (batch of 1,000 artifacts) - -## Data Flow - -```mermaid -sequenceDiagram - participant Buyer as Buyer Agent - participant Seller as Seller Agent - participant Verifier as Verification Agent - - Buyer->>Seller: get_media_buy_artifacts (sampled or full) - Seller-->>Buyer: Artifacts with content - Buyer->>Verifier: validate_content_delivery - Verifier-->>Buyer: Validation results -``` - -The buyer requests artifacts from the seller using the same media buy parameters. The seller returns content samples based on the agreed sampling rate. The buyer then validates these against the verification agent. - -## Request - -**Schema**: [get-media-buy-artifacts-request.json](https://adcontextprotocol.org/schemas/v2/content-standards/get-media-buy-artifacts-request.json) - -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `media_buy_id` | string | Yes | Media buy to get artifacts from | -| `package_ids` | array | No | Filter to specific packages | -| `sampling` | object | No | Sampling parameters (defaults to media buy agreement) | -| `time_range` | object | No | Filter to specific time period | -| `limit` | integer | No | Maximum artifacts to return (default: 1000) | -| `cursor` | string | No | Pagination cursor for large result sets | - -### Sampling Options - -```json -{ - "sampling": { - "rate": 0.25, - "method": "random" - } -} -``` - -| Method | Description | -|--------|-------------| -| `random` | Random sample across all deliveries | -| `stratified` | Sample proportionally across packages/properties | -| `recent` | Most recent deliveries first | -| `failures_only` | Only artifacts that failed local evaluation | - -## Response - -**Schema**: [get-media-buy-artifacts-response.json](https://adcontextprotocol.org/schemas/v2/content-standards/get-media-buy-artifacts-response.json) - -### Success Response - -```json -{ - "media_buy_id": "mb_nike_reddit_q1", - "artifacts": [ - { - "record_id": "imp_12345", - "timestamp": "2025-01-15T10:30:00Z", - "package_id": "pkg_feed_standard", - "artifact": { - "property_id": {"type": "domain", "value": "reddit.com"}, - "artifact_id": "r_fitness_abc123", - "assets": [ - {"type": "text", "role": "title", "content": "Best protein sources for muscle building", "language": "en"}, - {"type": "text", "role": "paragraph", "content": "Looking for recommendations on high-quality protein sources...", "language": "en"}, - {"type": "image", "url": "https://cdn.reddit.com/fitness-image.jpg", "alt_text": "Person lifting weights"} - ] - }, - "country": "US", - "channel": "social", - "brand_context": {"brand_id": "nike_global", "sku_id": "air_max_2025"}, - "local_verdict": "pass" - }, - { - "record_id": "imp_12346", - "timestamp": "2025-01-15T10:35:00Z", - "package_id": "pkg_feed_standard", - "artifact": { - "property_id": {"type": "domain", "value": "reddit.com"}, - "artifact_id": "r_news_politics_456", - "assets": [ - {"type": "text", "role": "title", "content": "Election Results Analysis", "language": "en"}, - {"type": "text", "role": "paragraph", "content": "The latest polling data shows...", "language": "en"} - ] - }, - "country": "US", - "channel": "social", - "brand_context": {"brand_id": "nike_global", "sku_id": "air_max_2025"}, - "local_verdict": "fail" - } - ], - "sampling_info": { - "total_deliveries": 100000, - "sampled_count": 1000, - "effective_rate": 0.01, - "method": "random" - }, - "pagination": { - "cursor": "eyJvZmZzZXQiOjEwMDB9", - "has_more": true - } -} -``` - -### Response Fields - -| Field | Description | -|-------|-------------| -| `artifacts` | Array of delivery records with full artifact content | -| `artifacts[].country` | ISO 3166-1 alpha-2 country code where delivery occurred | -| `artifacts[].channel` | Channel type (display, video, audio, social) | -| `artifacts[].brand_context` | Brand/SKU information for policy evaluation (schema TBD) | -| `artifacts[].local_verdict` | Seller's local model verdict (pass/fail/unevaluated) | -| `sampling_info` | How the sample was generated | -| `pagination` | Cursor for fetching more results | - -## Use Cases - -### Validate Sample Against Standards - -```python -# Get artifacts from seller -artifacts_response = seller_agent.get_media_buy_artifacts( - media_buy_id="mb_nike_reddit_q1", - sampling={"rate": 0.25, "method": "random"} -) - -# Convert to validation records -records = [ - { - "record_id": a["record_id"], - "timestamp": a["timestamp"], - "media_buy_id": artifacts_response["media_buy_id"], - "artifact": a["artifact"], - "country": a.get("country"), - "channel": a.get("channel"), - "brand_context": a.get("brand_context") - } - for a in artifacts_response["artifacts"] -] - -# Validate against verification agent -validation = verification_agent.validate_content_delivery( - standards_id="nike_brand_safety", - records=records -) - -# Check for drift between local and verified verdicts -for i, result in enumerate(validation["results"]): - local = artifacts_response["artifacts"][i]["local_verdict"] - verified = result["verdict"] - if local != verified: - print(f"Drift detected: {result['record_id']} - local={local}, verified={verified}") -``` - -### Focus on Local Failures - -```python -# Get only artifacts that failed local evaluation -failures = seller_agent.get_media_buy_artifacts( - media_buy_id="mb_nike_reddit_q1", - sampling={"method": "failures_only"}, - limit=100 -) - -# Verify these were correctly flagged -validation = verification_agent.validate_content_delivery( - standards_id="nike_brand_safety", - records=[{"record_id": a["record_id"], "artifact": a["artifact"]} - for a in failures["artifacts"]] -) - -# Check false positive rate -false_positives = sum(1 for r in validation["results"] if r["verdict"] == "pass") -print(f"False positive rate: {false_positives / len(failures['artifacts']):.1%}") -``` - -## Delivery vs Artifacts - -| Aspect | get_media_buy_delivery | get_media_buy_artifacts | -|--------|------------------------|-------------------------| -| **Purpose** | Performance reporting | Content validation | -| **Data size** | Small (metrics) | Large (full content) | -| **Frequency** | Regular reporting | Sampled validation | -| **Contains** | Impressions, clicks, spend | Text, images, video | -| **Consumer** | Buyer for optimization | Verification agent | - -## Related Tasks - -- [validate_content_delivery](/docs/governance/content-standards/tasks/validate_content_delivery) - Validate the artifacts -- [calibrate_content](/docs/governance/content-standards/tasks/calibrate_content) - Understand why artifacts pass/fail -- [get_media_buy_delivery](/docs/media-buy/task-reference/get_media_buy_delivery) - Get performance metrics diff --git a/v2.6-rc/docs/governance/content-standards/tasks/list_content_standards.mdx b/v2.6-rc/docs/governance/content-standards/tasks/list_content_standards.mdx deleted file mode 100644 index cdaea651ae..0000000000 --- a/v2.6-rc/docs/governance/content-standards/tasks/list_content_standards.mdx +++ /dev/null @@ -1,67 +0,0 @@ ---- -title: list_content_standards -sidebar_position: 2 ---- - -# list_content_standards - -List available content standards configurations. - -**Response time**: < 500ms - -## Request - -**Schema**: [list-content-standards-request.json](https://adcontextprotocol.org/schemas/v2/content-standards/list-content-standards-request.json) - -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `countries` | array | No | Filter by country codes | -| `channels` | array | No | Filter by channels | -| `languages` | array | No | Filter by BCP 47 language tags | - -## Response - -**Schema**: [list-content-standards-response.json](https://adcontextprotocol.org/schemas/v2/content-standards/list-content-standards-response.json) - -Returns an abbreviated list of standards configurations. Use [get_content_standards](/docs/governance/content-standards/tasks/get_content_standards) to retrieve full details including policy text and calibration data. - -### Success Response - -```json -{ - "standards": [ - { - "standards_id": "emea_digital_safety", - "name": "EMEA - all digital channels", - "countries_all": ["GB", "DE", "FR"], - "channels_any": ["display", "video", "ctv"], - "languages": ["en", "de", "fr"] - }, - { - "standards_id": "us_display_only", - "name": "US - display only", - "countries_all": ["US"], - "channels_any": ["display"], - "languages": ["en"] - } - ] -} -``` - -### Error Response - -```json -{ - "errors": [ - { - "code": "UNAUTHORIZED", - "message": "Invalid or expired token" - } - ] -} -``` - -## Related Tasks - -- [get_content_standards](/docs/governance/content-standards/tasks/get_content_standards) - Get a specific standards configuration -- [create_content_standards](/docs/governance/content-standards/tasks/create_content_standards) - Create a new configuration diff --git a/v2.6-rc/docs/governance/content-standards/tasks/update_content_standards.mdx b/v2.6-rc/docs/governance/content-standards/tasks/update_content_standards.mdx deleted file mode 100644 index 4f2fb5bc29..0000000000 --- a/v2.6-rc/docs/governance/content-standards/tasks/update_content_standards.mdx +++ /dev/null @@ -1,72 +0,0 @@ ---- -title: update_content_standards -sidebar_position: 6 ---- - -# update_content_standards - -Update an existing content standards configuration. Creates a new version. - -**Response time**: < 1s - -## Request - -**Schema**: [update-content-standards-request.json](https://adcontextprotocol.org/schemas/v2/content-standards/update-content-standards-request.json) - -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `standards_id` | string | Yes | ID of the standards configuration to update | -| `scope` | object | No | Updated scope | -| `policy` | string | No | Updated policy prompt | -| `calibration_exemplars` | object | No | Updated training exemplars (pass/fail) | - -### Example Request - -```json -{ - "standards_id": "nike_emea_safety", - "policy": "Sports and fitness content is ideal. Lifestyle content about health and wellness is good. Entertainment content is generally acceptable. Avoid violence, controversial politics, adult themes. Block hate speech and illegal activities.", - "calibration_exemplars": { - "pass": [ - { "type": "url", "value": "https://espn.com/nba/story/_/id/12345/lakers-win", "language": "en" }, - { "type": "url", "value": "https://healthline.com/fitness/cardio-workout", "language": "en" }, - { "type": "url", "value": "https://runnersworld.com/training/marathon-tips", "language": "en" } - ], - "fail": [ - { "type": "url", "value": "https://tabloid.example.com/celebrity-scandal", "language": "en" }, - { "type": "url", "value": "https://gambling.example.com/betting-guide", "language": "en" } - ] - } -} -``` - -## Response - -**Schema**: [update-content-standards-response.json](https://adcontextprotocol.org/schemas/v2/content-standards/update-content-standards-response.json) - -### Success Response - -```json -{ - "standards_id": "nike_emea_safety" -} -``` - -### Error Response - -```json -{ - "errors": [ - { - "code": "STANDARDS_NOT_FOUND", - "message": "No standards found with ID 'invalid_id'" - } - ] -} -``` - -## Related Tasks - -- [get_content_standards](/docs/governance/content-standards/tasks/get_content_standards) - Get current configuration -- [create_content_standards](/docs/governance/content-standards/tasks/create_content_standards) - Create a new configuration -- [delete_content_standards](/docs/governance/content-standards/tasks/delete_content_standards) - Delete a configuration diff --git a/v2.6-rc/docs/governance/content-standards/tasks/validate_content_delivery.mdx b/v2.6-rc/docs/governance/content-standards/tasks/validate_content_delivery.mdx deleted file mode 100644 index 97f36c2b71..0000000000 --- a/v2.6-rc/docs/governance/content-standards/tasks/validate_content_delivery.mdx +++ /dev/null @@ -1,183 +0,0 @@ ---- -title: validate_content_delivery -sidebar_position: 4 ---- - -# validate_content_delivery - -Validate delivery records against content safety policies. Designed for batch auditing of where ads were actually delivered. - -**Asynchronous**: Accept immediately, process in background. Returns a `validation_id` for status polling. - -## Data Flow - -Content artifacts are separate from delivery metrics. Use `get_media_buy_artifacts` to retrieve content for validation: - -```mermaid -sequenceDiagram - participant Buyer as Buyer Agent - participant Seller as Seller Agent - participant Verifier as Verification Agent - - Buyer->>Seller: get_media_buy_artifacts (sampled) - Seller-->>Buyer: Artifacts with content - Buyer->>Verifier: validate_content_delivery - Verifier-->>Buyer: Validation results -``` - -**Why through the buyer?** - -- The **buyer** owns the media buy and knows which `standards_id` applies -- The **buyer** requests artifacts from sellers (separate from performance metrics) -- The **buyer** is accountable for brand safety compliance -- The **verification agent** works on behalf of the buyer - -This keeps responsibilities clear: sellers provide content samples via `get_media_buy_artifacts`, buyers validate samples against the verification agent. - -## Request - -**Schema**: [validate-content-delivery-request.json](https://adcontextprotocol.org/schemas/v2/content-standards/validate-content-delivery-request.json) - -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `standards_id` | string | Yes | Standards configuration to validate against | -| `records` | array | Yes | Delivery records to validate (max 10,000) | -| `feature_ids` | array | No | Specific features to evaluate (defaults to all) | -| `include_passed` | boolean | No | Include passed records in results (default: true) | - -### Delivery Record - -```json -{ - "record_id": "imp_12345", - "timestamp": "2025-01-15T10:30:00Z", - "media_buy_id": "mb_nike_reddit_q1", - "artifact": { - "property_id": {"type": "domain", "value": "example.com"}, - "artifact_id": "article_12345", - "assets": [ - {"type": "text", "role": "title", "content": "Article Title"} - ] - }, - "country": "US", - "channel": "display", - "brand_context": { - "brand_id": "nike_global", - "sku_id": "air_max_2025" - } -} -``` - -| Field | Required | Description | -|-------|----------|-------------| -| `record_id` | Yes | Unique identifier for this delivery record | -| `artifact` | Yes | Content artifact where ad was delivered | -| `media_buy_id` | No | Media buy this record belongs to (for multi-buy batches) | -| `timestamp` | No | When the delivery occurred | -| `country` | No | ISO 3166-1 alpha-2 country code for targeting context | -| `channel` | No | Channel type (display, video, audio, social) | -| `brand_context` | No | Brand/SKU information for policy evaluation (schema TBD) | - -## Response - -**Schema**: [validate-content-delivery-response.json](https://adcontextprotocol.org/schemas/v2/content-standards/validate-content-delivery-response.json) - -### Success Response - -```json -{ - "summary": { - "total_records": 1000, - "passed_records": 950, - "failed_records": 50, - "total_features": 5000, - "passed_features": 4750, - "failed_features": 250 - }, - "results": [ - { - "record_id": "imp_12345", - "features": [ - { - "feature_id": "brand_safety", - "status": "passed", - "value": "safe" - } - ] - }, - { - "record_id": "imp_12346", - "features": [ - { - "feature_id": "brand_safety", - "status": "failed", - "value": "high_risk", - "message": "Content contains violence" - } - ] - } - ] -} -``` - -## Use Cases - -### Post-Campaign Audit - -```python -def audit_campaign_delivery(campaign_id, standards_id, content_standards_agent): - """Audit all delivery records from a campaign.""" - # Fetch delivery records from your ad server - records = fetch_delivery_records(campaign_id) - - # Validate in batches - batch_size = 10000 - all_results = [] - - for i in range(0, len(records), batch_size): - batch = records[i:i + batch_size] - response = content_standards_agent.validate_content_delivery( - standards_id=standards_id, - records=batch - ) - all_results.extend(response["results"]) - - return all_results -``` - -### Real-Time Monitoring Sample - -```python -import random - -def sample_and_validate(records, standards_id, sample_size=1000): - """Validate a random sample for real-time monitoring.""" - sample = random.sample(records, min(sample_size, len(records))) - return content_standards_agent.validate_content_delivery( - standards_id=standards_id, - records=sample - ) -``` - -### Filter for Issues Only - -```python -# Only get failed records to reduce response size -response = content_standards_agent.validate_content_delivery( - standards_id="nike_emea_safety", - records=delivery_records, - include_passed=False # Only return failures -) - -for result in response["results"]: - print(f"Issue with {result['record_id']}") - for feature in result["features"]: - if feature["status"] == "failed": - print(f" - {feature['feature_id']}: {feature['message']}") -``` - -## Related Tasks - -- [get_media_buy_artifacts](/docs/governance/content-standards/tasks/get_media_buy_artifacts) - Get content artifacts from seller -- [calibrate_content](/docs/governance/content-standards/tasks/calibrate_content) - Understand why artifacts pass/fail -- [get_content_standards](/docs/governance/content-standards/tasks/get_content_standards) - Retrieve the policies diff --git a/v2.6-rc/docs/governance/index.mdx b/v2.6-rc/docs/governance/index.mdx deleted file mode 100644 index f08e368f2d..0000000000 --- a/v2.6-rc/docs/governance/index.mdx +++ /dev/null @@ -1,187 +0,0 @@ ---- -sidebar_position: 1 -title: Governance Protocol ---- - - -**Draft for AdCP 3.0** - These governance protocols are under active development by the AAO Governance Working Group. Feedback welcome via [GitHub Discussions](https://github.com/adcontextprotocol/adcp/discussions). - - -The Governance Protocol provides standardized mechanisms for compliance, brand safety, and quality control across advertising workflows. It enables specialized agents to evaluate, filter, and score advertising entities against configurable criteria. - -## Mission - -> Define and operate transparent, privacy-safe, brand-suitable campaign governance that encodes human heuristics in open protocol objects, making campaigns easy to launch, safe to scale, and measurable against verifiable outcomes for buyers, sellers, and auditors. - -## Protocol Domains - -The Governance Protocol covers four distinct governance domains: - -| Domain | What It Governs | Key Mechanisms | -|--------|-----------------|----------------| -| **[Property Governance](/docs/governance/property/index)** | Where ads can run | Property lists, compliance filtering, adagents.json authorization | -| **[Brand Standards](/docs/governance/brand-standards/index)** | Brand requirements | Brand manifests, creative guidelines, audience constraints | -| **Creative Governance** | What creatives are compliant | Format validation, content moderation, accessibility | -| **Campaign Governance** | What can be bought | Budget controls, approval workflows, policy compliance | - -Each domain has specialized governance agents that provide data, filtering, and scoring capabilities. - -## Working Group Areas - -The AAO Governance Working Group is developing standards across six areas that inform these protocols: - -| Area | Focus | Protocol Impact | -|------|-------|-----------------| -| Brand Safety & Suitability | Safe, appropriate ad contexts | Property Governance, Content filtering | -| Brand Manifesto & Standards Library | Machine-readable brand policies | Brand Standards | -| Creative Standards & Validation | Technical and ethical creative criteria | Creative Governance | -| Process & Human Oversight | Human-in-the-loop checkpoints | All protocols | -| Regulatory & Compliance | Legal and regional frameworks | All protocols | -| Measurement & Verification | Proving compliance | All protocols | - -## Architecture - -Governance agents operate across the **full campaign lifecycle**: - -- **Setup time**: Configure property lists, brand requirements, and compliance rules -- **Real-time**: Influence bid-time decisions through cached rules and scoring -- **Post-bid**: Measurement, verification, and reporting on compliance - -``` -┌─────────────────────────────────────────────────────────────────────────┐ -│ BUYER AGENT │ -│ - Aggregates governance from specialized agents │ -│ - Issues auth_tokens for sellers to access governance data │ -│ - Source of truth for compliant lists and brand requirements │ -└───────────────────────────┬─────────────────────────────────────────────┘ - │ create_property_list, webhooks - ┌───────────────────┼───────────────────┐ - ▼ ▼ ▼ -┌───────────────┐ ┌───────────────┐ ┌───────────────┐ -│ Consent Agent │ │ Scope3 Agent │ │ Brand Safety │ -│ (Compliance) │ │ │ │ Agent │ -├───────────────┤ ├───────────────┤ ├───────────────┤ -│ consent_qual │ │ carbon_score │ │ content_cat │ -│ tcf_version │ │ climate_risk │ │ brand_risk │ -│ coppa_cert │ │ green_host │ │ sentiment │ -└───────────────┘ └───────────────┘ └───────────────┘ - │ - │ get_property_list (with auth_token) - ▼ -┌─────────────────────────────────────────────────────────────────────────┐ -│ SELLER AGENT (DSP/SSP) │ -│ - Caches resolved property lists for bid-time decisions │ -│ - Receives updates via webhooks when lists change │ -└─────────────────────────────────────────────────────────────────────────┘ -``` - -## Common Patterns - -### Feature Discovery - -All governance agents advertise their capabilities via discovery tasks: - -```json -{ - "tool": "list_property_features", - "arguments": {} -} -``` - -Response: -```json -{ - "features": [ - { "feature_id": "consent_quality", "type": "quantitative", "range": { "min": 0, "max": 100 } }, - { "feature_id": "coppa_certified", "type": "binary" }, - { "feature_id": "carbon_score", "type": "quantitative", "range": { "min": 0, "max": 100 } } - ] -} -``` - -### Brand Manifest - -Buyers declare their brand identity, and governance agents automatically apply appropriate rules: - -```json -{ - "brand_manifest": { - "brand_name": "ToyBrand", - "industry": "toys", - "target_audience": "children_under_13" - } -} -``` - -When a governance agent sees this manifest, it automatically applies COPPA requirements, content filtering for children's brands, and other industry-specific rules. - -### Prompt-Based Policies - -Governance protocols support **natural language prompts** for policy definitions rather than rigid keyword lists: - -```json -{ - "policy": "Avoid content about violence, controversial politics, or adult themes. Sports news is excellent. Entertainment is generally acceptable.", - "exclusions_prompt": "Block content containing hate speech, illegal activities, or ongoing litigation against our company." -} -``` - -This enables AI-powered verification agents to understand context and nuance. - -### Webhook Notifications - -Governance agents notify subscribers when evaluations change: - -```json -{ - "webhook_url": "https://buyer.example.com/webhooks/list-changed", - "events": ["list_updated", "property_removed", "score_changed"] -} -``` - -## Integration with Media Buy - -The Media Buy Protocol consumes governance data at multiple stages: - -- **Product discovery**: Pass `property_list_ref` to `get_products` to filter inventory -- **Media buy creation**: Reference property lists to constrain where ads can run -- **Authorization**: adagents.json validates agent authority to sell properties - -```json -{ - "tool": "get_products", - "arguments": { - "brief": "UK video inventory for Q1", - "property_list_ref": { - "agent_url": "https://buyer-agent.example.com", - "list_id": "pl_q1_uk_premium", - "auth_token": "..." - } - } -} -``` - -## Getting Started - -**Buyers:** -1. Subscribe to governance agents for property data and brand safety -2. Create property lists with filters and brand manifests -3. Aggregate results into final compliant lists -4. Share references with sellers (with auth tokens) - -**Governance Agent Implementers:** -1. Implement feature discovery tasks (`list_property_features`, etc.) -2. Implement stateful list management (CRUD operations) -3. Support webhooks to notify when evaluations change -4. See the [Property Protocol Specification](/docs/governance/property/specification) for detailed implementation guidance - -## Protocol Sections - - - - Control where ads can run with property lists, compliance filtering, and publisher authorization via adagents.json. - - - Define brand requirements including creative guidelines, audience constraints, and industry-specific rules. - - diff --git a/v2.6-rc/docs/governance/property/index.mdx b/v2.6-rc/docs/governance/property/index.mdx deleted file mode 100644 index d4f8468777..0000000000 --- a/v2.6-rc/docs/governance/property/index.mdx +++ /dev/null @@ -1,227 +0,0 @@ ---- -sidebar_position: 1 -title: Overview ---- - - -**AdCP 3.0 Proposal** - This protocol is under development for AdCP 3.0. Feedback welcome via [GitHub Discussions](https://github.com/adcontextprotocol/adcp/discussions). - - -Property Governance standardizes how advertising properties (websites, apps, CTV, podcasts, billboards) are identified, authorized, enriched with data, and selected for campaigns. - -## Overview - -Property Governance addresses four distinct concerns: - -| Concern | Question | Owner | Mechanism | -|---------|----------|-------|-----------| -| **Property Identity** | What properties exist? | Publishers | `adagents.json` properties array | -| **Sales Authorization** | Who can sell this property? | Publishers | `adagents.json` authorized_agents | -| **Property Data** | What do we know about this property? | Data providers | Governance agents via `list_property_features` | -| **Property Selection** | Which properties meet my requirements? | Buyers | Property lists with filters | - -The first two are **publisher-side declarations** via adagents.json. The last two are **buyer-side operations** that consume property data from governance agents. - -## Publisher Side: adagents.json - -Publishers declare their properties and authorize sales agents via `/.well-known/adagents.json`: - -```json -{ - "$schema": "https://adcontextprotocol.org/schemas/v2/adagents.json", - "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"] - } - ] -} -``` - -See the [adagents.json Tech Spec](/docs/governance/property/adagents) for complete documentation. - -## Buyer Side: Property Data and Selection - -### Property Data Providers - -Governance agents provide data about properties - compliance scores, brand safety ratings, sustainability metrics, etc. They advertise their capabilities via `list_property_features`: - -```json -{ - "features": [ - { "feature_id": "consent_quality", "type": "quantitative", "range": { "min": 0, "max": 100 } }, - { "feature_id": "coppa_certified", "type": "binary" }, - { "feature_id": "carbon_score", "type": "quantitative", "range": { "min": 0, "max": 100 } } - ] -} -``` - -Buyers send property lists to these agents, and the agents filter and score the properties based on their specialized data. Different agents specialize in different data: - -- **Compliance vendors** (data integrity, consent quality) -- **Brand safety providers** (content classification, risk scoring) -- **Quality measurement** (viewability, fraud detection) -- **Sustainability providers** (carbon scoring, green hosting) - -### Property Selection via Governance Agents - -Buyers create **property lists on governance agents** - the agents manage these lists and apply their filtering logic: - -```json -{ - "tool": "create_property_list", - "arguments": { - "name": "Q1 Campaign - UK Premium", - "base_properties": [ - { - "selection_type": "publisher_tags", - "publisher_domain": "raptive.com", - "tags": ["premium_news"] - } - ], - "filters": { - "countries_all": ["UK"], - "channels_any": ["display", "video"], - "feature_requirements": [ - { "feature_id": "consent_quality", "min_value": 85, "max_value": 100 } - ] - }, - "brand_manifest": { - "brand_name": "ToyBrand", - "industry": "toys", - "target_audience": "children_under_13" - } - } -} -``` - -When you provide a brand manifest, governance agents automatically apply appropriate rules (COPPA for children's brands, content filtering based on industry, etc.). - -A buyer agent typically works with **multiple governance agents** (consent, brand safety, sustainability) and aggregates/intersects their results into a final compliant list. - -## How It Fits Together - -```mermaid -flowchart TB - subgraph Buyer["BUYER AGENT"] - B1[Source of truth for compliant list] - B2[Aggregates results from specialized agents] - B3[Issues auth_tokens for sellers] - end - - subgraph Governance["GOVERNANCE AGENTS"] - CA["Consent Agent
consent_quality
tcf_version
coppa_certified"] - S3["Scope3 Agent
carbon_score
climate_risk
green_hosting"] - BS["Brand Safety Agent
content_category
brand_risk
sentiment"] - end - - subgraph Seller["SELLER AGENT (DSP/SSP)"] - SE1[Caches resolved property lists] - SE2[Uses cached lists for bid-time decisions] - end - - Buyer -->|create_property_list + webhooks| CA - Buyer -->|create_property_list + webhooks| S3 - Buyer -->|create_property_list + webhooks| BS - - Buyer -->|get_property_list with auth_token| Seller -``` - -## Sharing Property Lists with Sellers - -Once a buyer has a compliant property list, they share it with sellers: - -1. **Get a list reference**: The buyer agent exposes the list via `get_property_list` -2. **Issue an auth token**: The buyer generates a token that authorizes access to the list -3. **Pass to seller**: Include `property_list_ref` with `auth_token` in product discovery or media buy requests -4. **Seller caches locally**: Sellers fetch and cache the resolved list for bid-time decisions -5. **Webhooks for updates**: When the list changes, sellers are notified to refresh their cache - -```json -{ - "property_list_ref": { - "agent_url": "https://buyer-agent.example.com", - "list_id": "pl_q1_uk_premium", - "auth_token": "eyJhbGciOiJIUzI1NiIs..." - } -} -``` - -Sellers use this reference in `get_products` to filter available inventory: - -```json -{ - "tool": "get_products", - "arguments": { - "brief": "UK video inventory for Q1", - "property_list_ref": { - "agent_url": "https://buyer-agent.example.com", - "list_id": "pl_q1_uk_premium", - "auth_token": "..." - } - } -} -``` - -## Relationship to Other Protocols - -### Property Governance + Media Buy - -The Media Buy Protocol consumes property lists at multiple stages: - -- **Product discovery**: Pass `property_list_ref` to `get_products` to filter inventory to compliant properties -- **Media buy creation**: Reference property lists to constrain where ads can run -- **Authorization**: adagents.json validates agent authority to sell - -### Property Governance + Signals - -Both protocols operate on properties but serve different purposes: - -| Signals Protocol | Property Governance | -|------------------|---------------------| -| Audience/contextual data | Property metadata and compliance | -| "Who should see this ad?" | "Where can this ad run?" | -| Signal activation | Property filtering | - -## Tasks - -### Discovery - -- **[list_property_features](/docs/governance/property/tasks/list_property_features)**: Discover what data a governance agent can provide about properties - -### Property List Management - -- **[create_property_list](/docs/governance/property/tasks/property_lists#create_property_list)**: Create a new property list on a governance agent -- **[get_property_list](/docs/governance/property/tasks/property_lists#get_property_list)**: Retrieve resolved properties (with caching guidance) -- **[update_property_list](/docs/governance/property/tasks/property_lists#update_property_list)**: Modify filters or base properties -- **[delete_property_list](/docs/governance/property/tasks/property_lists#delete_property_list)**: Remove a property list - -## Getting Started - -**Publishers:** -1. Create `/.well-known/adagents.json` with property definitions -2. Authorize sales agents for your properties - -**Buyers:** -1. Subscribe to governance agents for property data -2. Create property lists on each governance agent with filters and brand manifests -3. Aggregate results into a final compliant list -4. Share property list references with sellers (with auth tokens) - -**Governance Agent Implementers:** -1. Implement `list_property_features` to advertise your capabilities -2. Implement property list CRUD operations -3. Support webhooks to notify buyers when evaluations change -4. See the [Protocol Specification](/docs/governance/property/specification) for implementation details - -See the [Protocol Specification](/docs/governance/property/specification) for detailed implementation guidance. diff --git a/v2.6-rc/docs/governance/property/specification.mdx b/v2.6-rc/docs/governance/property/specification.mdx deleted file mode 100644 index 343d1c7e32..0000000000 --- a/v2.6-rc/docs/governance/property/specification.mdx +++ /dev/null @@ -1,611 +0,0 @@ ---- -sidebar_position: 2 -title: Protocol Specification ---- - - -**AdCP 3.0 Proposal** - This specification is under development for AdCP 3.0. Feedback welcome via [GitHub Discussions](https://github.com/adcontextprotocol/adcp/discussions). - - -**Status**: Request for Comments -**Last Updated**: January 2026 - -## Abstract - -The Property Protocol defines a standard Model Context Protocol (MCP) and Agent-to-Agent (A2A) interface for property identity, authorization, data provision, and selection. This protocol enables publishers to declare properties and authorized agents, data providers to offer property intelligence, and buyers to select compliant property sets. - -## Overview - -The Property Protocol addresses four distinct concerns: - -| Concern | Question | Owner | Mechanism | -|---------|----------|-------|-----------| -| **Property Identity** | What properties exist? | Publishers | `adagents.json` properties array | -| **Sales Authorization** | Who can sell this property? | Publishers | `adagents.json` authorized_agents | -| **Property Data** | What do we know about this property? | Data providers | Governance agents via `list_property_features` | -| **Property Selection** | Which properties meet my requirements? | Buyers | Property lists with filters | - -The first two are **publisher-side declarations** via adagents.json. The last two are **buyer-side operations** that consume property data from governance agents. - -### Property Data and Selection - -Property data and selection use a **stateful** model: - -- **Feature discovery**: Agents advertise what they can evaluate via `list_property_features` -- **Property list management**: CRUD operations for managed property lists with filters -- **Brand manifests**: Let agents automatically apply rules based on brand characteristics -- **Webhook notifications**: Real-time updates when resolved lists change -- **Marketplace architecture**: Multiple specialized agents as subscription services - -All evaluation (scoring, filtering, discovery) happens implicitly when property lists are resolved via `get_property_list`. - -## Core Concepts - -### Request Roles and Relationships - -Every governance request involves two key roles: - -#### Orchestrator (Buyer Agent) -The platform or system making the API request to the governance agent. In AdCP documentation, this role is often called a "buyer agent" when operating in the media buying context. -- **Examples**: DSP, trading desk platform, campaign management tool -- **Responsibilities**: Makes API calls, handles authentication, manages the technical interaction -- **Account**: Has technical credentials and API access to the governance agent - -#### Principal -The entity on whose behalf the request is being made: -- **Examples**: Advertiser (Nike), agency (Omnicom), brand team -- **Responsibilities**: Owns the campaign objectives and policy requirements -- **Policies**: May have custom thresholds, blocklists, or compliance requirements - -### Property Identification - -Properties are identified using the standard AdCP property model: - -```json -{ - "property_type": "website", - "name": "Example News", - "identifiers": [ - { "type": "domain", "value": "example.com" } - ] -} -``` - -Property types include: `website`, `mobile_app`, `ctv_app`, `dooh`, `podcast`, `radio`, `streaming_audio`. - -### Property List References - -For large property sets, use property list references instead of embedding properties: - -```json -{ - "property_list_ref": { - "agent_url": "https://lists.example.com", - "list_id": "premium_news_sites", - "auth_token": "eyJhbGciOiJIUzI1NiIs..." - } -} -``` - -The receiving agent fetches and caches the list independently, enabling: -- **Scale**: Pass 50,000+ properties without payload bloat -- **Updates**: Lists evolve without changing requests -- **Authorization**: Token controls access to the list - -### Governance Agent Types - -#### Compliance Agents -Specialized vendors providing property compliance intelligence: -- **Examples**: Data integrity scoring, consent quality measurement -- **Business Model**: Subscription or per-query pricing -- **Methodology**: Published rubrics for transparency - -#### Brand Safety Agents -Content classification and risk assessment: -- **Examples**: Content categorization, brand safety scoring -- **Coverage**: May specialize by channel or geography - -#### Quality Agents -Performance and fraud measurement: -- **Examples**: Viewability prediction, IVT detection -- **Integration**: May correlate with campaign outcomes - -### Scoring and Data Privacy - -#### Scores Are Internal - -**Critical design principle**: Raw scores are NOT shared with buyers or downstream clients. This prevents data leakage. - -Governance agents maintain internal scoring models, but the protocol is designed around **list management**, not score exposure: - -- Buyers specify **thresholds** via `feature_requirements` (e.g., `"min_value": 85`) -- Agents return **pass/fail lists** of properties that meet the thresholds -- Raw scores never leave the governance agent - -This design prevents: -- Score enumeration attacks (running lists with different thresholds to reverse-engineer scores) -- Competitive intelligence leakage -- Data arbitrage where buyers resell scoring data - -#### What Buyers Receive - -When calling `get_property_list`, buyers receive a compact list of identifiers (not full property objects) for efficiency: - -```json -{ - "list_id": "pl_abc123", - "identifiers": [ - { "type": "domain", "value": "bbc.co.uk" }, - { "type": "domain", "value": "theguardian.com" }, - { "type": "domain", "value": "ft.com" } - ], - "total_count": 847 -} -``` - -Properties that pass the threshold are included. Properties that fail are excluded. No scores or property metadata are returned - just the identifiers needed for bid-time lookups. - -#### Methodology Discovery - -The `list_property_features` task returns information about what features an agent evaluates and their methodology, but NOT the underlying scores: - -```json -{ - "features": [ - { - "feature_id": "consent_quality", - "name": "Consent Quality Score", - "type": "quantitative", - "range": { "min": 0, "max": 100 }, - "methodology": "data_integrity_index", - "methodology_version": "v2.1", - "methodology_url": "https://compliance.example.com/methodology" - } - ] -} -``` - -This allows buyers to: -- Understand what an agent measures -- Compare methodologies across agents -- Set appropriate thresholds - -But they cannot retrieve the actual scores for individual properties. - -## Tasks - -### Discovery - -#### list_property_features - -Discover what features a governance agent can evaluate. - -**Use Cases**: -- Capability discovery: Understand what an agent can evaluate -- Marketplace browsing: Compare features across agents -- Integration planning: Know what filters are available before creating lists - -### Property List Management - -#### create_property_list - -Create a new property list with filters and optional brand manifest. - -**Required Parameters**: -- At least one country in `countries_all` (ISO country code) -- At least one channel in `channels_any` (display, video, audio, etc.) - -**Base Properties**: An array of property sources to evaluate. Each entry is a discriminated union with `selection_type` as the discriminator: -- **`publisher_tags`**: `{ "selection_type": "publisher_tags", "publisher_domain": "...", "tags": [...] }` - tags scoped to publisher -- **`publisher_ids`**: `{ "selection_type": "publisher_ids", "publisher_domain": "...", "property_ids": [...] }` - property IDs scoped to publisher -- **`identifiers`**: `{ "selection_type": "identifiers", "identifiers": [...] }` - no publisher context needed -- **Omitted**: Query the agent's entire property database - -See the [base-property-source schema](https://adcontextprotocol.org/schemas/v2/property/base-property-source.json) for the full specification. - -**Filter Logic** (explicit in field names): -- `countries_all`: Property must have feature data for **ALL** listed countries -- `channels_any`: Property must support **ANY** of the listed channels -- `feature_requirements`: Property must pass **ALL** requirements (AND) - -**Use Cases**: -- Define compliant property sets with filters (country, channel, feature thresholds) -- Provide brand manifest for automatic rule application -- Register webhook URL for change notifications - -#### update_property_list - -Modify an existing property list. - -**Use Cases**: -- Add or remove properties from base list -- Adjust filters based on campaign needs -- Update webhook URL - -#### get_property_list - -Retrieve a property list with resolved properties. - -**Use Cases**: -- Get the current list of compliant properties after filters applied -- Cache resolved list for bid-time use -- Retrieve updated list after webhook notification - -#### list_property_lists - -List all property lists accessible to the authenticated principal. - -#### delete_property_list - -Remove a property list. - -### Validation - -#### validate_property_delivery - -Validates delivery records against a property list to determine compliance. Closes the loop between "what I wanted" and "what I got." - -Performs two independent validations: -1. **Property compliance**: Is the identifier in the resolved property list? -2. **Supply path authorization**: Was the sales agent authorized to sell that property? (optional, requires `sales_agent_url`) - -**Use Cases**: -- Post-campaign validation: Verify impressions landed on compliant properties -- Supply path verification: Confirm sales agents were authorized by publishers -- Real-time monitoring: Check compliance rate during campaign execution -- Audit trails: Generate compliance reports for regulatory or brand safety reviews - -**Property Validation Statuses**: -- `compliant`: Identifier is in the resolved property list -- `non_compliant`: Identifier is NOT in the resolved property list -- `not_covered`: Identifier recognized but governance agent has no data for it (e.g., property too new) -- `unidentified`: Identifier type not resolvable by this agent (e.g., detection failed, unsupported type) - -**Authorization Validation Statuses** (when `sales_agent_url` provided): -- `authorized`: Sales agent is listed in publisher's adagents.json -- `unauthorized`: Sales agent is NOT in publisher's authorized_agents list -- `unknown`: Could not fetch or parse adagents.json - -**Unverifiable Records**: Both `not_covered` and `unidentified` records should be excluded when calculating compliance rates - you cannot penalize for detection gaps or coverage limitations. The distinction helps identify whether the gap is in the agent's data coverage vs the identifier resolution. - -**Response Format**: The response returns raw counts (compliant, non_compliant, not_covered, unidentified impressions). Consumers calculate rates as needed. Governance agents may optionally include an `aggregate` field with computed metrics (score, grade, label) - the format and meaning are agent-specific. - -## Typical Flows - -### Property List Flow - -Property lists enable buyers to define and manage compliant property sets: - -1. **Create property list**: Buyer defines list on governance agent with filters -2. **Resolve and iterate**: Buyer calls `get_property_list` to see resolved properties -3. **Share list reference**: Buyer provides `list_id` to orchestrator/seller -4. **Cache locally**: Orchestrator/seller fetches and caches resolved properties -5. **Use at bid time**: Orchestrator/seller uses local cache (no governance agent calls) -6. **Refresh periodically**: Re-fetch based on `cache_valid_until` (typically 1-24 hours) - -**Important**: Governance agents are NOT in the real-time bid path. All bid-time decisions use locally cached property sets. - -### Webhook and Caching Pattern - -Webhooks provide **notification** that a property list has changed. The webhook payload contains a summary of changes, but you must call `get_property_list` to retrieve the actual updated properties. - -``` -┌─────────────────────────────────────────────────────────────────┐ -│ Webhook Flow │ -├─────────────────────────────────────────────────────────────────┤ -│ │ -│ 1. Governance agent re-evaluates properties (background) │ -│ 2. Webhook fires with change summary (added/removed counts) │ -│ 3. Recipient calls get_property_list to fetch updated list │ -│ 4. Recipient updates local cache │ -│ │ -└─────────────────────────────────────────────────────────────────┘ -``` - -**Best Practices for Downstream Consumers**: - -Consumers of property lists (orchestrators, sellers, buyer agents) should implement **at least one** of these patterns: - -1. **Webhook-driven updates** (recommended): Register a webhook URL when creating the property list. Re-fetch via `get_property_list` when notified of changes. - -2. **Polling with cache hints**: Use `cache_valid_until` from `get_property_list` responses to schedule periodic re-fetches. Typical validity periods are 1-24 hours. - -3. **Hybrid approach**: Use webhooks for immediate updates, with polling as a fallback safety net. - -**Cache Expiry Guidance**: - -Every `get_property_list` response includes: -- `resolved_at`: When the list was evaluated -- `cache_valid_until`: When consumers should consider the cache stale - -```json -{ - "resolved_at": "2026-01-04T10:00:00Z", - "cache_valid_until": "2026-01-04T22:00:00Z" -} -``` - -Consumers MUST NOT use cached data beyond `cache_valid_until` without re-fetching. - -### Property Discovery Flow - -1. **Define filters**: Specify country, channel, quality thresholds when creating property list -2. **Resolve list**: Call `get_property_list` with `resolve=true` to get matching properties -3. **Review candidates**: Evaluate returned properties for fit -4. **Add to campaign**: Include property list reference in media buy - -## Response Structure - -All AdCP Governance responses follow a consistent structure: - -### Core Response Fields -- **message**: Human-readable summary of the operation result -- **context_id**: Session continuity identifier for follow-up requests -- **data**: Task-specific payload (varies by task) - -### Protocol Transport -- **MCP**: Returns complete response as flat JSON object -- **A2A**: Returns as structured artifacts with message in text part, data in data part -- **Data Consistency**: Both protocols contain identical AdCP data structures - -## Error Handling - -### Error Codes - -- `PROPERTY_NOT_FOUND`: Property identifier not recognized -- `PROPERTY_NOT_MONITORED`: Governance agent doesn't cover this property -- `POLICY_NOT_FOUND`: Referenced policy doesn't exist -- `LIST_ACCESS_DENIED`: Cannot access property list (auth failed) -- `LIST_NOT_FOUND`: Property list reference invalid -- `METHODOLOGY_NOT_SUPPORTED`: Requested methodology version unavailable -- `PARTIAL_RESULTS`: Some properties couldn't be evaluated - -### Partial Success - -For bulk operations, the response may include partial results: - -```json -{ - "message": "Evaluated 847 of 850 properties. 3 properties not in coverage.", - "context_id": "ctx-gov-123", - "scores": [...], - "errors": [ - { - "code": "PROPERTY_NOT_MONITORED", - "property": { "identifiers": [{ "type": "domain", "value": "unknown.com" }] }, - "message": "Property not in monitoring coverage" - } - ] -} -``` - -## Implementation Notes - -### Caching Architecture - -Governance decisions are highly cacheable: - -#### Orchestrator-Side Caching -- **Score cache**: Store scores with TTL from `valid_until` field -- **Decision cache**: Pre-compute pass/fail for campaigns -- **List cache**: Cache property lists from `property_list_ref` - -#### Agent-Side Caching -- **Profile cache**: Maintain pre-computed property profiles -- **Methodology cache**: Cache scoring algorithm results - -### Performance Requirements - -| Operation | Target Latency | -|-----------|----------------| -| Single property score | < 100ms | -| Bulk scoring (100 properties) | < 2s | -| Filter decision (cached) | < 5ms | -| Property discovery | < 5s | - -### Multi-Agent Strategies - -Orchestrators may consult multiple governance agents: - -1. **Primary + Validation**: Use primary agent, validate with secondary -2. **Specialization**: Route by property type to specialist agents -3. **Consensus**: Require multiple agents to agree -4. **Competitive**: Track agent accuracy, weight by performance - -## Agent Discovery - -Governance agents expose capabilities via `.well-known/agent-card.json`: - -```json -{ - "name": "Example Compliance Provider", - "url": "https://compliance.example.com", - "capabilities": { - "tasks": [ - "list_property_features", - "create_property_list", - "get_property_list", - "update_property_list", - "delete_property_list", - "list_property_lists", - "validate_property_delivery" - ], - "protocols": ["MCP", "A2A"], - "schema_version": "v1" - }, - "methodology": { - "documentation_url": "https://compliance.example.com/methodology", - "scoring_frameworks": ["data_integrity_index", "brand_safety_score"], - "coverage": { - "property_types": ["website", "mobile_app", "ctv_app"], - "jurisdictions": ["GDPR", "CCPA", "COPPA"] - } - } -} -``` - -Use `list_property_features` for detailed capability discovery: - -```json -{ - "tool": "list_property_features", - "arguments": {} -} -``` - -Returns the specific features the agent can evaluate (consent_quality, carbon_score, brand_risk, etc.). - -## Marketplace Architecture - -The Property Protocol enables a marketplace of specialized data agents: - -``` -┌─────────────────────────────────────────────────────────────────────────┐ -│ SELLER AGENT (DSP/SSP) │ -│ "Give me the compliant property list for this campaign" │ -└───────────────────────────────┬─────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────────────────┐ -│ BUYER AGENT (implements Property Protocol) │ -│ - Exposes: list_property_features, get_property_list, webhooks │ -│ - Source of truth for final compliant list │ -│ - Intersects results from specialized agents │ -└───────────────────────────┬─────────────────────────────────────────────┘ - │ - ┌───────────────────┼───────────────────┐ - ▼ ▼ ▼ -┌───────────────┐ ┌───────────────┐ ┌───────────────┐ -│ Consent Agent │ │ Scope3 Agent │ │ Brand Safety │ -│ (Compliant) │ │ │ │ Agent │ -├───────────────┤ ├───────────────┤ ├───────────────┤ -│ Features: │ │ Features: │ │ Features: │ -│ consent_qual │ │ carbon_score │ │ content_cat │ -│ tcf_version │ │ climate_risk │ │ brand_risk │ -│ coppa_cert │ │ green_host │ │ sentiment │ -├───────────────┤ ├───────────────┤ ├───────────────┤ -│ Subscription │ │ Subscription │ │ Subscription │ -└───────────────┘ └───────────────┘ └───────────────┘ -``` - -### Key Principles - -1. **Buyer agent is source of truth**: The buyer agent aggregates data from multiple specialized governance agents -2. **Seller sees one interface**: Sellers interact only with the buyer agent using standard Property Protocol -3. **Subscription model**: Each specialized agent is a paid service with its own features and coverage -4. **Webhook-driven updates**: Specialized agents notify the buyer agent when property evaluations change - -### Multi-Agent Orchestration - -A buyer agent can distribute a master property list to multiple specialized agents: - -```python -# Buyer agent creates variants on each specialized agent -consent_list = consent_agent.create_property_list( - name="Q1 Campaign - Consent", - base_properties=master_list, - brand_manifest=brand_manifest -) -# Configure webhook for updates -consent_agent.update_property_list( - list_id=consent_list.list_id, - webhook_url="https://buyer.example.com/webhooks/consent" -) - -scope3_list = scope3_agent.create_property_list( - name="Q1 Campaign - Sustainability", - base_properties=master_list, - brand_manifest=brand_manifest -) -scope3_agent.update_property_list( - list_id=scope3_list.list_id, - webhook_url="https://buyer.example.com/webhooks/scope3" -) - -# Buyer agent intersects filtered results -def on_list_changed(event): - consent_props = consent_agent.get_property_list(consent_list.list_id, resolve=True) - scope3_props = scope3_agent.get_property_list(scope3_list.list_id, resolve=True) - - # Intersection = properties that pass ALL governance agents - compliant_props = intersect(consent_props, scope3_props) - - # Update buyer agent's exposed list - update_compliant_list(compliant_props) -``` - -### Brand Manifest - -Instead of specifying complex filters, buyers provide a brand manifest: - -```json -{ - "brand_manifest": { - "brand_name": "ToyBrand", - "industry": "toys", - "target_audience": "children_under_13", - "content_adjacency": ["kids_family", "education"], - "excluded_content": ["violence", "adult"] - } -} -``` - -Each governance agent interprets the manifest according to their domain expertise: -- **Consent agent**: Applies COPPA requirements for children_under_13 -- **Brand safety agent**: Filters to kids_family content, excludes violence/adult -- **Sustainability agent**: Applies any green media requirements - -The buyer doesn't need to know the specific rules - they declare who they are, and agents figure out what applies. - -## Integration with Media Buy Protocol - -### Property Lists in Media Buys - -The Media Buy Protocol accepts property list references: - -```json -{ - "task": "create_media_buy", - "arguments": { - "packages": [{ - "property_list_ref": { - "agent_url": "https://governance.example.com", - "list_id": "approved_q1_campaign", - "auth_token": "..." - } - }] - } -} -``` - -### Policy Compliance - -Media buys can reference governance policies via property list references: - -```json -{ - "compliance_requirements": { - "property_list_ref": { - "agent_url": "https://compliance.example.com", - "list_id": "pl_q1_compliant", - "auth_token": "eyJhbGciOiJIUzI1NiIs..." - } - } -} -``` - -## Best Practices - -1. **Cache aggressively**: Property scores change slowly; cache for hours/days -2. **Bulk where possible**: Use batch operations for planning, not per-property calls -3. **Pre-compute decisions**: Build pass/fail lookups before bid-time -4. **Monitor coverage**: Track which properties agents don't cover -5. **Log methodology versions**: For audit trails, record which scoring version was used -6. **Handle partial results**: Not all properties will be scorable; plan for gaps - -## Next Steps - -- See the [adagents.json Tech Spec](/docs/governance/property/adagents) for property declaration and authorization -- See the [list_property_features task reference](/docs/governance/property/tasks/list_property_features) for capability discovery -- See the [Property List Management](/docs/governance/property/tasks/property_lists) for CRUD operations and webhooks -- See the [validate_property_delivery task reference](/docs/governance/property/tasks/validate_property_delivery) for post-campaign compliance validation diff --git a/v2.6-rc/docs/governance/property/tasks/index.mdx b/v2.6-rc/docs/governance/property/tasks/index.mdx deleted file mode 100644 index 4679e3704b..0000000000 --- a/v2.6-rc/docs/governance/property/tasks/index.mdx +++ /dev/null @@ -1,153 +0,0 @@ ---- -sidebar_position: 1 -title: Task Reference ---- - -# Property Governance Tasks - - -**AdCP 3.0 Proposal** - These tasks are under development for AdCP 3.0. - - -Property governance uses a **stateful** model where all evaluation happens through property list management. Create lists with filters and brand manifests, then resolve them to get compliant properties. - -## Discovery - -| Task | Purpose | Response Time | -|------|---------|---------------| -| [list_property_features](/docs/governance/property/tasks/list_property_features) | Discover agent capabilities | ~200ms | - -## Property List Management - -| Task | Purpose | Response Time | -|------|---------|---------------| -| [create_property_list](/docs/governance/property/tasks/property_lists#create_property_list) | Create a new property list | ~500ms | -| [update_property_list](/docs/governance/property/tasks/property_lists#update_property_list) | Modify an existing list | ~500ms | -| [get_property_list](/docs/governance/property/tasks/property_lists#get_property_list) | Retrieve list with resolved properties | ~2-5s | -| [list_property_lists](/docs/governance/property/tasks/property_lists#list_property_lists) | List all property lists | ~500ms | -| [delete_property_list](/docs/governance/property/tasks/property_lists#delete_property_list) | Delete a property list | ~200ms | - -See [Property List Management](/docs/governance/property/tasks/property_lists) for complete CRUD documentation. - -## Validation - -| Task | Purpose | Response Time | -|------|---------|---------------| -| [validate_property_delivery](/docs/governance/property/tasks/validate_property_delivery) | Validate delivery records against a list | ~1-5s | - -See [validate_property_delivery](/docs/governance/property/tasks/validate_property_delivery) for post-campaign compliance validation. - -## Task Selection Guide - -### Creating a Property List - -Use `create_property_list` with filters and brand manifest: - -```json -{ - "tool": "create_property_list", - "arguments": { - "name": "Q1 Campaign - UK Premium", - "base_properties": [ - { - "selection_type": "publisher_tags", - "publisher_domain": "raptive.com", - "tags": ["premium_news"] - } - ], - "filters": { - "countries_all": ["UK"], - "channels_any": ["display", "video"], - "feature_requirements": [ - { - "feature_id": "consent_quality", - "min_value": 85, - "max_value": 100 - }, - { - "feature_id": "coppa_certified", - "allowed_values": [true] - } - ] - }, - "brand_manifest": { - "name": "ToyBrand", - "industry": "toys", - "target_audience": "children_under_13" - } - } -} -``` - -**Required filters**: At least one country in `countries_all` and one channel in `channels_any` must be provided. - -**Base properties**: An array of property sources to evaluate. Each entry is a discriminated union with `selection_type`: -- **`publisher_tags`**: `{ "selection_type": "publisher_tags", "publisher_domain": "...", "tags": [...] }` -- **`publisher_ids`**: `{ "selection_type": "publisher_ids", "publisher_domain": "...", "property_ids": [...] }` -- **`identifiers`**: `{ "selection_type": "identifiers", "identifiers": [...] }` -- **Omitted**: Query the agent's entire property database - -**Filter logic** (explicit in field names): -- `countries_all`: Property must have feature data for ALL listed countries -- `channels_any`: Property must support ANY of the listed channels -- `feature_requirements`: Property must pass ALL requirements (AND) - -Filters have two built-in fields (`countries_all`, `channels_any`) plus `feature_requirements` which reference features the agent provides (discovered via `list_property_features`). For quantitative features, use `min_value`/`max_value`. For binary or categorical features, use `allowed_values`. - -### Getting Resolved Properties - -Use `get_property_list` to retrieve the list with resolved identifiers: - -```json -{ - "tool": "get_property_list", - "arguments": { - "list_id": "pl_abc123", - "resolve": true - } -} -``` - -Response includes resolved identifiers. Note that **raw scores are not returned** - only identifiers that pass the filter thresholds are included: - -```json -{ - "list_id": "pl_abc123", - "identifiers": [ - { "type": "domain", "value": "bbc.co.uk" }, - { "type": "domain", "value": "news.sky.com" } - ], - "cache_valid_until": "2026-01-04T17:15:00Z" -} -``` - -The `auth_token` for sharing with sellers is returned at creation time (from `create_property_list`). Store it securely - it's only returned once. - -### Multi-Agent Integration - -Create the same property list on multiple governance agents, then configure webhooks to aggregate results: - -```python -# Create lists on specialized agents -consent_list = consent_agent.create_property_list( - name="Q1 - Consent", - base_properties=master_list, - brand_manifest=brand_manifest -) -consent_agent.update_property_list( - list_id=consent_list.list_id, - webhook_url="https://buyer.example.com/webhooks/consent" -) - -scope3_list = scope3_agent.create_property_list( - name="Q1 - Sustainability", - base_properties=master_list, - brand_manifest=brand_manifest -) -scope3_agent.update_property_list( - list_id=scope3_list.list_id, - webhook_url="https://buyer.example.com/webhooks/scope3" -) - -# Buyer agent intersects results when webhooks fire -``` diff --git a/v2.6-rc/docs/governance/property/tasks/list_property_features.mdx b/v2.6-rc/docs/governance/property/tasks/list_property_features.mdx deleted file mode 100644 index 6c7dcd16a7..0000000000 --- a/v2.6-rc/docs/governance/property/tasks/list_property_features.mdx +++ /dev/null @@ -1,235 +0,0 @@ ---- -sidebar_position: 1 -title: list_property_features ---- - - -**AdCP 3.0 Proposal** - This task is under development for AdCP 3.0. - - -**Task**: Discover what features a property governance agent can evaluate. - -**Response Time**: ~200ms - -**Request Schema**: [`https://adcontextprotocol.org/schemas/v1/governance/list-property-features-request.json`](https://adcontextprotocol.org/schemas/v1/governance/list-property-features-request.json) -**Response Schema**: [`https://adcontextprotocol.org/schemas/v1/governance/list-property-features-response.json`](https://adcontextprotocol.org/schemas/v1/governance/list-property-features-response.json) - -The `list_property_features` task returns the features a governance agent can evaluate. This is the discovery mechanism for understanding an agent's capabilities before using other governance tasks. - -## Request Parameters - -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `property_types` | string[] | No | Filter to features available for these property types | -| `countries` | string[] | No | Filter to features available in these countries | - -## Response Structure - -All AdCP responses include: -- **message**: Human-readable summary of the operation result -- **context_id**: Session continuity identifier for follow-up requests -- **data**: Task-specific payload (see Response Data below) - -## Response Data - -```json -{ - "features": [ - { - "feature_id": "consent_quality", - "name": "Consent Quality Score", - "description": "Measures the quality of consent implementation including UX, granularity, and compliance", - "type": "quantitative", - "range": { "min": 0, "max": 100 }, - "coverage": { - "property_types": ["website", "mobile_app"], - "countries": [] - } - }, - { - "feature_id": "coppa_certified", - "name": "COPPA Certified", - "description": "Whether the property has COPPA certification for child-directed content", - "type": "binary", - "coverage": { - "property_types": ["website", "mobile_app", "ctv_app"], - "countries": ["US"] - } - }, - { - "feature_id": "content_category", - "name": "Content Category", - "description": "IAB content category classification", - "type": "categorical", - "allowed_values": ["news", "sports", "entertainment", "kids_family", "technology", "business", "adult", "violence"] - } - ] -} -``` - -### Feature Types - -| Type | Description | Schema Fields | -|------|-------------|---------------| -| `binary` | True/false values | None additional | -| `quantitative` | Numeric values within a range | `range: { min, max }` | -| `categorical` | Enumerated string values | `allowed_values: string[]` | - -### Coverage - -The `coverage` object indicates where a feature applies: -- **property_types**: Empty array means all property types -- **countries**: Empty array means all countries - -## Protocol-Specific Examples - -### MCP Request - -```json -{ - "tool": "list_property_features", - "arguments": {} -} -``` - -### MCP Response - -```json -{ - "message": "This agent evaluates 12 features across consent, brand safety, and sustainability.", - "context_id": "ctx-gov-features-123", - "features": [ - { - "feature_id": "consent_quality", - "name": "Consent Quality Score", - "description": "Measures the quality of consent implementation", - "type": "quantitative", - "range": { "min": 0, "max": 100 } - }, - { - "feature_id": "tcf_version", - "name": "TCF Version", - "description": "IAB Transparency & Consent Framework version supported", - "type": "categorical", - "allowed_values": ["none", "tcf_1.1", "tcf_2.0", "tcf_2.2"] - }, - { - "feature_id": "coppa_certified", - "name": "COPPA Certified", - "description": "Whether property has COPPA certification", - "type": "binary", - "coverage": { - "property_types": ["website", "mobile_app", "ctv_app"], - "countries": ["US"] - } - } - ] -} -``` - -### MCP Request - Filtered by Property Type - -```json -{ - "tool": "list_property_features", - "arguments": { - "property_types": ["mobile_app"] - } -} -``` - -### A2A Request - -```javascript -await a2a.send({ - message: { - parts: [{ - kind: "data", - data: { - skill: "list_property_features", - parameters: {} - } - }] - } -}); -``` - -## Example Feature Sets by Agent Type - -### Consent/Compliance Agent - -```json -{ - "features": [ - { "feature_id": "consent_quality", "type": "quantitative", "range": { "min": 0, "max": 100 } }, - { "feature_id": "tcf_version", "type": "categorical", "allowed_values": ["none", "tcf_2.0", "tcf_2.2"] }, - { "feature_id": "coppa_certified", "type": "binary" }, - { "feature_id": "gpp_supported", "type": "binary" }, - { "feature_id": "vendor_count", "type": "quantitative", "range": { "min": 0, "max": 1000 } } - ] -} -``` - -### Sustainability Agent (e.g., Scope3) - -```json -{ - "features": [ - { "feature_id": "carbon_score", "type": "quantitative", "range": { "min": 0, "max": 100 } }, - { "feature_id": "green_certified", "type": "binary" }, - { "feature_id": "renewable_hosting", "type": "binary" }, - { "feature_id": "emissions_per_impression", "type": "quantitative", "range": { "min": 0, "max": 100 } } - ] -} -``` - -### Brand Safety Agent - -```json -{ - "features": [ - { "feature_id": "content_category", "type": "categorical", "allowed_values": ["news", "sports", ...] }, - { "feature_id": "brand_risk_score", "type": "quantitative", "range": { "min": 0, "max": 100 } }, - { "feature_id": "sentiment", "type": "categorical", "allowed_values": ["positive", "neutral", "negative"] }, - { "feature_id": "made_for_advertising", "type": "binary" } - ] -} -``` - -## Integration Pattern - -Use `list_property_features` to understand agent capabilities before creating property lists: - -```python -# Step 1: Discover agent capabilities -features_response = governance_agent.list_property_features() - -# Step 2: Build feature_requirements using available features -feature_requirements = [] -for feature in features_response.features: - if feature.feature_id == "consent_quality" and feature.type == "quantitative": - feature_requirements.append({ - "feature_id": "consent_quality", - "min_value": 80, - "max_value": 100 - }) - if feature.feature_id == "coppa_certified" and feature.type == "binary": - feature_requirements.append({ - "feature_id": "coppa_certified", - "allowed_values": [True] - }) - -# Step 3: Create property list with feature requirements -governance_agent.create_property_list( - name="Q1 Campaign", - filters={"feature_requirements": feature_requirements}, - brand_manifest=my_brand_manifest -) -``` - -## Usage Notes - -1. **Call first**: Use this task to discover capabilities before other governance tasks -2. **Cache results**: Feature definitions change infrequently; cache for hours/days -3. **Check coverage**: Not all features apply to all property types or countries -4. **Marketplace discovery**: Use this to understand what different governance agents offer diff --git a/v2.6-rc/docs/governance/property/tasks/property_lists.mdx b/v2.6-rc/docs/governance/property/tasks/property_lists.mdx deleted file mode 100644 index a46e54545f..0000000000 --- a/v2.6-rc/docs/governance/property/tasks/property_lists.mdx +++ /dev/null @@ -1,701 +0,0 @@ ---- -sidebar_position: 5 -title: Property List Management ---- - - -**AdCP 3.0 Proposal** - These tasks are under development for AdCP 3.0. - - -**Tasks**: Create, update, get, list, and delete property lists. - -Property lists are managed resources that combine static property sets with dynamic filters. When resolved, filters are applied to produce the final property set. - -## Architecture: Setup Time, Not Real-Time - -Property lists are designed for **setup-time** operations, not real-time bid decisions: - -``` -┌─────────────────────────────────────────────────────────────────┐ -│ SETUP TIME (Campaign Planning) │ -├─────────────────────────────────────────────────────────────────┤ -│ │ -│ 1. Buyer creates/updates property list on governance agent │ -│ 2. Buyer resolves list to get current properties │ -│ 3. Buyer provides list_id to orchestrator/seller │ -│ 4. Orchestrator/seller fetches and caches resolved list │ -│ 5. Campaign targets only cached compliant properties │ -│ │ -└─────────────────────────────────────────────────────────────────┘ - -┌─────────────────────────────────────────────────────────────────┐ -│ BID TIME (Milliseconds) │ -├─────────────────────────────────────────────────────────────────┤ -│ │ -│ • Orchestrator/seller uses LOCAL cache only │ -│ • NO calls to governance agent │ -│ • Pass/fail from cached property set │ -│ │ -└─────────────────────────────────────────────────────────────────┘ - -┌─────────────────────────────────────────────────────────────────┐ -│ REFRESH (Periodic) │ -├─────────────────────────────────────────────────────────────────┤ -│ │ -│ • Orchestrator/seller re-fetches list on schedule │ -│ • Frequency based on cache_valid_until │ -│ • Typically every 1-24 hours │ -│ │ -└─────────────────────────────────────────────────────────────────┘ -``` - -This enables: - -- **Static lists**: Curated sets of approved properties -- **Dynamic lists**: Properties matching criteria (country, channel, score thresholds) -- **Hybrid lists**: Base set modified by filters - -## Tasks Overview - -| Task | Purpose | Response Time | -|------|---------|---------------| -| `create_property_list` | Create a new property list | ~500ms | -| `update_property_list` | Modify an existing list | ~500ms | -| `get_property_list` | Retrieve list with resolved properties | ~2-5s (depending on size) | -| `list_property_lists` | List all property lists | ~500ms | -| `delete_property_list` | Delete a property list | ~200ms | - -## Property List Structure - -A property list contains: - -```json -{ - "list_id": "uk_premium_news_q1", - "name": "UK Premium News Sites Q1 2026", - "description": "High-quality UK news sites for Q1 campaign", - "principal": "did:principal:brand-x", - "base_properties": [ - { - "selection_type": "publisher_tags", - "publisher_domain": "raptive.com", - "tags": ["premium_news", "uk_tier1"] - } - ], - "filters": { - "countries_all": ["UK"], - "channels_any": ["display", "video"], - "feature_requirements": [ - { "feature_id": "consent_quality", "min_value": 90, "max_value": 100 } - ] - }, - "brand_manifest": { - "industry": "retail", - "target_audience": "general" - }, - "created_at": "2026-01-03T10:00:00Z", - "updated_at": "2026-01-03T10:00:00Z", - "property_count": 847 -} -``` - -## Brand Manifest - -Instead of manually specifying all filters, provide a brand manifest and let the governance agent apply appropriate rules based on who you are: - -```json -{ - "brand_manifest": { - "name": "ToyBrand", - "industry": "toys", - "target_audience": "children under 13", - "tone": "playful and safe" - } -} -``` - -The agent interprets the manifest based on its domain expertise: -- A consent agent applies COPPA requirements based on `target_audience` -- A brand safety agent infers content categories from `industry` -- A sustainability agent applies requirements from the brand's profile - -The brand manifest uses the standard [core/brand-manifest](https://adcontextprotocol.org/schemas/v2/core/brand-manifest.json) schema which includes fields for `industry`, `target_audience`, `tone`, and other brand identity information. - -## Webhooks - -Configure webhooks via `update_property_list` to receive notifications when the resolved list changes. - -**Important**: Webhooks provide **notification only**. They tell you that the list has changed, but do not stream the updated properties. After receiving a webhook, you must call `get_property_list` to retrieve the updated property set. - -### Webhook Flow - -``` -1. Governance agent re-evaluates properties (periodically or on trigger) -2. Agent detects changes to the resolved property list -3. Webhook fires with change summary (counts, not full list) -4. Recipient calls get_property_list(list_id, resolve=true) -5. Recipient updates local cache with new properties -``` - -### Webhook Payload - -```json -{ - "event": "property_list_changed", - "list_id": "uk_premium_news_q1", - "list_name": "UK Premium News Sites Q1 2026", - "change_summary": { - "properties_added": 12, - "properties_removed": 3, - "total_properties": 856 - }, - "resolved_at": "2026-01-03T18:00:00Z", - "cache_valid_until": "2026-01-04T18:00:00Z" -} -``` - -The webhook payload includes counts but NOT the actual properties. This keeps payloads small and avoids redundant data transfer when recipients may not need the full list immediately. - -### Webhook Use Cases - -1. **Buyer agent aggregation**: Receive updates from multiple specialized agents, intersect results -2. **Seller cache invalidation**: Know when to re-fetch the compliant property list -3. **Alerting**: Notify when significant changes occur to compliance status - -## Filters - -Filters are applied when the list is resolved (via `get_property_list`): - -| Filter | Type | Description | -|--------|------|-------------| -| `countries_all` | string[] | ISO country codes - property must have feature data for ALL (required) | -| `channels_any` | string[] | Advertising channels - property must support ANY (required) | -| `property_types` | string[] | Property types (website, mobile_app, ctv_app, etc.) | -| `feature_requirements` | FeatureRequirement[] | Requirements based on agent-provided features | -| `exclude_identifiers` | Identifier[] | Identifiers to always exclude | - -### Feature Requirements - -Feature requirements reference features discovered via `list_property_features`. Each agent exposes different features (consent_quality, carbon_score, coppa_certified, etc.). - -For **quantitative** features (scores, ranges): -```json -{ "feature_id": "consent_quality", "min_value": 85, "max_value": 100 } -``` - -For **binary** features (true/false): -```json -{ "feature_id": "coppa_certified", "allowed_values": [true] } -``` - -For **categorical** features (enum values): -```json -{ "feature_id": "content_category", "allowed_values": ["news", "sports", "technology"] } -``` - -### Handling Missing Coverage - -When a property doesn't have data for a required feature, you can control the behavior with `if_not_covered`: - -```json -{ - "feature_id": "viewability_score", - "min_value": 70, - "if_not_covered": "include" -} -``` - -| Value | Behavior | Use Case | -|-------|----------|----------| -| `exclude` (default) | Property is removed from the list | Strict enforcement - only include properties with verified data | -| `include` | Property passes this requirement | Lenient enforcement - don't penalize for coverage gaps | - -When `if_not_covered: "include"` is used, the response includes a `coverage_gaps` field showing which properties were included despite missing data: - -```json -{ - "identifiers": [...], - "coverage_gaps": { - "viewability_score": [ - { "type": "domain", "value": "app.example.com" }, - { "type": "domain", "value": "ctv.example.com" } - ] - } -} -``` - -This transparency helps agencies distinguish between properties that passed a requirement vs. those that couldn't be evaluated. - -### Required Filters - -Every property list must include at least: -- One country in `countries_all` (ISO country code) -- One channel in `channels_any` (display, video, audio, etc.) - -These are required because governance agents need to know which jurisdiction and context to evaluate properties against. - -### Filter Logic - -The filter field names make the logic explicit: - -- **`countries_all`**: Property must have feature data for **ALL** listed countries. -- **`channels_any`**: Property must support **ANY** of the listed channels. -- **`feature_requirements`**: Property must pass **ALL** requirements (AND). - -### Base Properties - -`base_properties` is an array of property sources to evaluate. Each entry is a **discriminated union** with `selection_type` as the discriminator: - -```json -{ - "base_properties": [ - { - "selection_type": "publisher_tags", - "publisher_domain": "raptive.com", - "tags": ["premium_news", "tier1"] - }, - { - "selection_type": "publisher_tags", - "publisher_domain": "mediavine.com", - "tags": ["lifestyle"] - }, - { - "selection_type": "identifiers", - "identifiers": [ - { "type": "domain", "value": "bbc.co.uk" }, - { "type": "domain", "value": "ft.com" } - ] - } - ] -} -``` - -Each entry must include `selection_type`: - -| selection_type | Required Fields | Description | -|-------------|-----------------|-------------| -| `publisher_tags` | `publisher_domain`, `tags` | All properties matching these tags within the publisher | -| `publisher_ids` | `publisher_domain`, `property_ids` | Specific property IDs within the publisher | -| `identifiers` | `identifiers` | Direct domain/app identifiers (no publisher context) | - -If `base_properties` is omitted, the agent queries its entire property database for properties matching the filters. - -See the [base-property-source schema](https://adcontextprotocol.org/schemas/v2/property/base-property-source.json) for the full specification. - ---- - -## create_property_list - -Create a new property list. - -### Request - -```json -{ - "tool": "create_property_list", - "arguments": { - "name": "UK Premium News Q1", - "description": "High-quality UK news sites for Q1 campaign", - "base_properties": [ - { - "selection_type": "publisher_tags", - "publisher_domain": "raptive.com", - "tags": ["premium_news"] - } - ], - "filters": { - "countries_all": ["UK"], - "channels_any": ["display", "video"], - "feature_requirements": [ - { "feature_id": "consent_quality", "min_value": 85, "max_value": 100 } - ] - } - } -} -``` - -### Response - -```json -{ - "message": "Created property list 'UK Premium News Q1'.", - "context_id": "ctx-gov-list-123", - "list": { - "list_id": "pl_abc123", - "name": "UK Premium News Q1", - "description": "High-quality UK news sites for Q1 campaign", - "principal": "did:principal:brand-x", - "base_properties": [ - { - "selection_type": "publisher_tags", - "publisher_domain": "raptive.com", - "tags": ["premium_news"] - } - ], - "filters": { - "countries_all": ["UK"], - "channels_any": ["display", "video"], - "feature_requirements": [ - { "feature_id": "consent_quality", "min_value": 85, "max_value": 100 } - ] - }, - "created_at": "2026-01-03T16:30:00Z", - "updated_at": "2026-01-03T16:30:00Z", - "property_count": 847 - }, - "auth_token": "eyJhbGciOiJIUzI1NiIs..." -} -``` - -### Dynamic List (Filters Only) - -Create a list that dynamically queries the governance agent's database (no base_properties - uses agent's full coverage): - -```json -{ - "tool": "create_property_list", - "arguments": { - "name": "GDPR-Compliant DE Video", - "description": "All DE properties supporting video with strong consent", - "filters": { - "countries_all": ["DE"], - "channels_any": ["video"], - "feature_requirements": [ - { "feature_id": "consent_quality", "min_value": 90, "max_value": 100 } - ] - } - } -} -``` - ---- - -## update_property_list - -Modify an existing property list. - -### Request - Update Filters - -```json -{ - "tool": "update_property_list", - "arguments": { - "list_id": "pl_abc123", - "filters": { - "countries_all": ["UK"], - "channels_any": ["display", "video"], - "feature_requirements": [ - { "feature_id": "consent_quality", "min_value": 80, "max_value": 100 } - ] - } - } -} -``` - -### Request - Replace Base Properties - -```json -{ - "tool": "update_property_list", - "arguments": { - "list_id": "pl_abc123", - "base_properties": [ - { - "selection_type": "publisher_tags", - "publisher_domain": "raptive.com", - "tags": ["premium_news", "uk_tier1"] - } - ] - } -} -``` - -### Request - Add Exclusions - -```json -{ - "tool": "update_property_list", - "arguments": { - "list_id": "pl_abc123", - "filters": { - "exclude_identifiers": [ - { "type": "domain", "value": "excluded-site.com" } - ] - } - } -} -``` - -### Response - -```json -{ - "message": "Updated property list 'UK Premium News Q1'.", - "context_id": "ctx-gov-list-456", - "list": { - "list_id": "pl_abc123", - "name": "UK Premium News Q1", - "updated_at": "2026-01-03T17:00:00Z", - "property_count": 845 - } -} -``` - ---- - -## get_property_list - -Retrieve a property list with optional resolution of filters. - -### Request - Get Resolved Properties - -```json -{ - "tool": "get_property_list", - "arguments": { - "list_id": "pl_abc123", - "resolve": true, - "max_results": 100 - } -} -``` - -### Response - -The response returns a compact list of **identifiers only** (not full property objects) for efficiency. Only identifiers that pass the feature requirements are included - no scores or metadata. - -```json -{ - "message": "Retrieved property list 'UK Premium News Q1' with 847 resolved identifiers.", - "context_id": "ctx-gov-list-789", - "list_id": "pl_abc123", - "identifiers": [ - { "type": "domain", "value": "bbc.co.uk" }, - { "type": "domain", "value": "news.sky.com" }, - { "type": "domain", "value": "ft.com" }, - { "type": "domain", "value": "theguardian.com" } - ], - "total_count": 847, - "returned_count": 100, - "pagination": { - "has_more": true, - "cursor": "eyJvZmZzZXQiOjEwMH0=" - }, - "resolved_at": "2026-01-03T17:15:00Z", - "cache_valid_until": "2026-01-04T17:15:00Z" -} -``` - - -The `auth_token` is only returned when the list is created via `create_property_list`. Store it securely - you'll need it to share access with sellers. - - -### Request - Get Metadata Only - -```json -{ - "tool": "get_property_list", - "arguments": { - "list_id": "pl_abc123", - "resolve": false - } -} -``` - -### Response (Metadata Only) - -```json -{ - "message": "Retrieved property list 'UK Premium News Q1' metadata.", - "context_id": "ctx-gov-list-790", - "list": { - "list_id": "pl_abc123", - "name": "UK Premium News Q1", - "description": "High-quality UK news sites for Q1 campaign", - "base_properties": [ - { - "selection_type": "publisher_tags", - "publisher_domain": "raptive.com", - "tags": ["premium_news"] - } - ], - "filters": { - "countries_all": ["UK"], - "channels_any": ["display", "video"], - "feature_requirements": [ - { "feature_id": "consent_quality", "min_value": 85, "max_value": 100 } - ] - }, - "created_at": "2026-01-03T16:30:00Z", - "updated_at": "2026-01-03T17:00:00Z", - "property_count": 847 - } -} -``` - ---- - -## list_property_lists - -List all property lists accessible to the authenticated principal. - -### Request - -```json -{ - "tool": "list_property_lists", - "arguments": { - "name_contains": "UK", - "max_results": 50 - } -} -``` - -### Response - -```json -{ - "message": "Found 3 property lists matching 'UK'.", - "context_id": "ctx-gov-list-list-123", - "lists": [ - { - "list_id": "pl_abc123", - "name": "UK Premium News Q1", - "description": "High-quality UK news sites for Q1 campaign", - "created_at": "2026-01-03T16:30:00Z", - "updated_at": "2026-01-03T17:00:00Z", - "property_count": 847 - }, - { - "list_id": "pl_def456", - "name": "UK Sports Sites", - "description": "UK sports content for sponsorship", - "created_at": "2026-01-02T10:00:00Z", - "updated_at": "2026-01-02T10:00:00Z", - "property_count": 156 - } - ], - "total_count": 3, - "returned_count": 3, - "pagination": { - "has_more": false - } -} -``` - ---- - -## delete_property_list - -Delete a property list. - -### Request - -```json -{ - "tool": "delete_property_list", - "arguments": { - "list_id": "pl_abc123" - } -} -``` - -### Response - -```json -{ - "message": "Deleted property list 'UK Premium News Q1'.", - "context_id": "ctx-gov-list-del-123", - "deleted": true, - "list_id": "pl_abc123" -} -``` - ---- - -## Integration with Other Tasks - -### Using Lists in score_properties - -Reference a property list instead of passing properties inline: - -```json -{ - "tool": "score_properties", - "arguments": { - "property_list_ref": { - "agent_url": "https://governance.example.com", - "list_id": "pl_abc123" - }, - "scoring_context": { - "jurisdiction": "GDPR" - } - } -} -``` - -### Using Lists in Media Buys - -Pass property lists to media buy creation: - -```json -{ - "tool": "create_media_buy", - "arguments": { - "packages": [{ - "property_list_ref": { - "agent_url": "https://governance.example.com", - "list_id": "pl_abc123" - } - }] - } -} -``` - ---- - -## Error Codes - -| Code | Description | -|------|-------------| -| `LIST_NOT_FOUND` | Property list ID doesn't exist | -| `LIST_ACCESS_DENIED` | Principal doesn't have access to this list | -| `INVALID_FILTER` | Filter configuration is invalid | -| `LIST_NAME_EXISTS` | A list with this name already exists | - -## Caching and Refresh - -The `get_property_list` response includes caching guidance: - -| Field | Description | -|-------|-------------| -| `resolved_at` | When filters were applied and properties resolved | -| `cache_valid_until` | When consumers should re-fetch the list | - -**Typical flow for orchestrators/sellers:** - -```python -# Initial setup -response = governance_agent.get_property_list(list_id, resolve=True) -local_cache = build_property_lookup(response.properties) -cache_expiry = response.cache_valid_until - -# Periodic refresh (background job) -if now() >= cache_expiry: - response = governance_agent.get_property_list(list_id, resolve=True) - local_cache = build_property_lookup(response.properties) - cache_expiry = response.cache_valid_until - -# Bid time (no external calls) -def should_bid(property_domain): - return property_domain in local_cache -``` - -## Usage Notes - -1. **Setup time only**: Governance agents are not in the real-time bid path; resolve lists during campaign setup -2. **Local caching**: Orchestrators/sellers must cache resolved properties locally for bid-time decisions -3. **Refresh on schedule**: Re-fetch lists based on `cache_valid_until` (typically every 1-24 hours) -4. **Dynamic vs Static**: Use filters-only lists when you want the agent to maintain the property set; use base_properties when you need explicit control -5. **Pagination**: Large lists may require multiple requests with cursor-based pagination -6. **No score leakage**: Raw scores are kept internal to governance agents; responses contain pass/fail lists, not scores diff --git a/v2.6-rc/docs/governance/property/tasks/validate_property_delivery.mdx b/v2.6-rc/docs/governance/property/tasks/validate_property_delivery.mdx deleted file mode 100644 index 7f9acc8c42..0000000000 --- a/v2.6-rc/docs/governance/property/tasks/validate_property_delivery.mdx +++ /dev/null @@ -1,402 +0,0 @@ ---- -sidebar_position: 4 -title: validate_property_delivery ---- - -# validate_property_delivery - - -**AdCP 3.0 Proposal** - This task is under development for AdCP 3.0. - - -Validates delivery records against a property list to determine compliance. Answers two questions: -1. **Property compliance**: Did my impressions land on properties in my list? -2. **Supply path authorization**: Was the sales agent authorized to sell that inventory? - -## Use Cases - -- **Post-campaign validation**: Verify that impressions were delivered to compliant properties -- **Supply path verification**: Confirm sales agents were authorized by publishers -- **Real-time monitoring**: Check compliance rate during campaign execution -- **Audit trails**: Generate compliance reports for regulatory or brand safety reviews - -## Request - -```json -{ - "$schema": "/schemas/property/validate-property-delivery-request.json", - "list_id": "pl_abc123", - "records": [ - { - "identifier": { "type": "domain", "value": "www.nytimes.com" }, - "impressions": 103 - }, - { - "identifier": { "type": "domain", "value": "sketchy-site.example" }, - "impressions": 47 - }, - { - "identifier": { "type": "android_package", "value": "com.unknown.app" }, - "impressions": 25 - } - ], - "include_compliant": false -} -``` - -### Parameters - -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `list_id` | string | Yes | ID of the property list to validate against | -| `records` | array | Yes | Delivery records to validate (1-10,000 records) | -| `records[].identifier` | object | Yes | Property identifier (`type` and `value`) | -| `records[].impressions` | integer | Yes | Number of impressions delivered | -| `records[].record_id` | string | No | Client-provided ID for correlation | -| `records[].sales_agent_url` | string | No | Sales agent URL to validate authorization against adagents.json | -| `include_compliant` | boolean | No | Include compliant records in results (default: false) | - -## Response - -```json -{ - "$schema": "/schemas/property/validate-property-delivery-response.json", - "list_id": "pl_abc123", - "summary": { - "total_records": 4, - "total_impressions": 200, - "compliant_records": 1, - "compliant_impressions": 103, - "non_compliant_records": 1, - "non_compliant_impressions": 47, - "not_covered_records": 1, - "not_covered_impressions": 25, - "unidentified_records": 1, - "unidentified_impressions": 25 - }, - "aggregate": { - "score": 68.7, - "grade": "C+", - "label": "68.7% compliant", - "methodology_url": "https://governance.example.com/methodology/compliance-scoring" - }, - "results": [ - { - "identifier": { "type": "domain", "value": "sketchy-site.example" }, - "status": "non_compliant", - "impressions": 47, - "violations": [ - { - "code": "not_in_list", - "message": "Identifier not found in resolved property list" - } - ] - }, - { - "identifier": { "type": "domain", "value": "new-site.example" }, - "status": "not_covered", - "impressions": 25 - }, - { - "identifier": { "type": "android_package", "value": "com.unknown.app" }, - "status": "unidentified", - "impressions": 25 - } - ], - "validated_at": "2026-01-04T19:00:00Z", - "list_resolved_at": "2026-01-04T12:00:00Z" -} -``` - -### Response Fields - -| Field | Type | Description | -|-------|------|-------------| -| `list_id` | string | ID of the property list validated against | -| `summary` | object | Raw counts for property compliance validation | -| `aggregate` | object | Optional computed metrics from the governance agent | -| `results` | array | Per-record validation results | -| `validated_at` | datetime | When validation was performed | -| `list_resolved_at` | datetime | Resolution timestamp of the property list used | - -### Summary Fields - -The summary provides raw counts - consumers calculate rates as needed: - -| Field | Description | -|-------|-------------| -| `total_records` | Total records validated | -| `total_impressions` | Total impressions across all records | -| `compliant_records` / `compliant_impressions` | Records/impressions in the property list | -| `non_compliant_records` / `non_compliant_impressions` | Records/impressions NOT in the property list | -| `not_covered_records` / `not_covered_impressions` | Identifier recognized but no data available | -| `unidentified_records` / `unidentified_impressions` | Identifier type not resolvable | - -### Validation Statuses - -| Status | Meaning | -|--------|---------| -| `compliant` | Identifier is in the resolved property list | -| `non_compliant` | Identifier is NOT in the resolved property list | -| `not_covered` | Identifier recognized but governance agent has no data for it | -| `unidentified` | Identifier type not resolvable by this agent | - -## Understanding not_covered vs unidentified - -These two statuses distinguish different types of "unknown" scenarios: - -**`not_covered`** - The governance agent recognized the identifier (e.g., it's a valid domain) but doesn't have data for that specific property. This happens when: -- A property is too new to be in the agent's database -- The property exists but hasn't been evaluated yet -- The agent's coverage doesn't include that property category - -**`unidentified`** - The governance agent couldn't recognize the identifier at all. This happens when: -- Client-side detection failed to capture the property -- The identifier type isn't supported (e.g., agent handles domains but received an app ID) -- The identifier value is malformed or invalid - -Both statuses should be excluded from compliance rate calculations - you cannot penalize for detection or coverage gaps. - -## Optional Aggregate Metrics - -Governance agents can optionally return computed metrics in the `aggregate` field: - -```json -"aggregate": { - "score": 68.7, - "grade": "C+", - "label": "68.7% compliant", - "methodology_url": "https://governance.example.com/methodology" -} -``` - -| Field | Description | -|-------|-------------| -| `score` | Numeric score (scale is agent-defined, typically 0-100) | -| `grade` | Letter grade or category (e.g., "A+", "B-", "Gold") | -| `label` | Human-readable summary (e.g., "85% compliant") | -| `methodology_url` | URL explaining how the aggregate was calculated | - -The `aggregate` field is optional and agent-specific. Consumers should not assume a particular format - always check `methodology_url` for interpretation. - -## Calculating Your Own Rates - -The response always includes raw counts. Calculate rates as needed: - -```python -# Compliance rate (exclude unverifiable from denominator) -unverifiable = summary.not_covered_impressions + summary.unidentified_impressions -verifiable = summary.total_impressions - unverifiable -compliance_rate = summary.compliant_impressions / verifiable if verifiable > 0 else None -``` - -In the example above: -- Compliant impressions: 103 -- Non-compliant impressions: 47 -- not_covered + unidentified impressions: 50 (excluded) -- Compliance rate: 103 / (200 - 50) = 103 / 150 = 68.7% - -## Violation Codes - -| Code | Description | -|------|-------------| -| `not_in_list` | Identifier not found in the resolved property list | -| `excluded` | Identifier explicitly excluded via `exclude_identifiers` filter | -| `country_mismatch` | Property lacks feature data for required countries | -| `channel_mismatch` | Property doesn't support required channels | -| `feature_failed` | Property failed a `feature_requirements` filter | - -### Feature Violation Details - -When a property fails a feature requirement, the violation includes the feature details: - -```json -{ - "identifier": { "type": "domain", "value": "low-quality-site.example" }, - "status": "non_compliant", - "impressions": 150, - "violations": [ - { - "code": "feature_failed", - "message": "Property failed consent_quality requirement (min: 85)", - "feature_id": "consent_quality", - "requirement": { - "min_value": 85 - } - } - ] -} -``` - -The `feature_id` and `requirement` fields are optional - they're included when the violation is due to a feature requirement filter. - -## Supply Path Authorization - -When `sales_agent_url` is provided in delivery records, the governance agent validates that the sales agent is authorized to sell the property by checking the publisher's `adagents.json`. - -### Request with Authorization - -```json -{ - "list_id": "pl_abc123", - "records": [ - { - "identifier": { "type": "domain", "value": "www.nytimes.com" }, - "impressions": 103, - "sales_agent_url": "https://legitimate-ssp.example.com" - }, - { - "identifier": { "type": "domain", "value": "www.nytimes.com" }, - "impressions": 50, - "sales_agent_url": "https://unauthorized-reseller.example.com" - } - ] -} -``` - -### Response with Authorization - -When authorization is validated, each result includes an `authorization` field: - -```json -{ - "list_id": "pl_abc123", - "summary": { - "total_records": 2, - "total_impressions": 153, - "compliant_records": 2, - "compliant_impressions": 153, - "non_compliant_records": 0, - "non_compliant_impressions": 0, - "unknown_records": 0, - "unknown_impressions": 0 - }, - "authorization_summary": { - "records_checked": 2, - "impressions_checked": 153, - "authorized_records": 1, - "authorized_impressions": 103, - "unauthorized_records": 1, - "unauthorized_impressions": 50, - "unknown_records": 0, - "unknown_impressions": 0 - }, - "results": [ - { - "identifier": { "type": "domain", "value": "www.nytimes.com" }, - "status": "compliant", - "impressions": 50, - "authorization": { - "status": "unauthorized", - "publisher_domain": "nytimes.com", - "sales_agent_url": "https://unauthorized-reseller.example.com", - "violation": { - "code": "agent_not_authorized", - "message": "Sales agent not listed in nytimes.com/.well-known/adagents.json" - } - } - } - ], - "validated_at": "2026-01-04T19:00:00Z" -} -``` - -### Authorization Statuses - -| Status | Meaning | Included in authorization_rate? | -|--------|---------|--------------------------------| -| `authorized` | Sales agent is listed in publisher's adagents.json | Yes (numerator) | -| `unauthorized` | Sales agent is NOT listed in publisher's adagents.json | Yes (denominator only) | -| `unknown` | Could not fetch or parse adagents.json | No (excluded) | - -### Authorization Violation Codes - -| Code | Description | -|------|-------------| -| `agent_not_authorized` | Sales agent URL not found in publisher's authorized_agents list | -| `adagents_not_found` | Publisher's adagents.json could not be fetched (404, timeout, etc.) | -| `adagents_invalid` | Publisher's adagents.json exists but is malformed | -| `property_not_declared` | Property identifier not declared in publisher's adagents.json | - -### Two Independent Checks - -Property compliance and authorization are **independent checks**. A record can be: - -| Property Status | Authorization Status | Meaning | -|-----------------|---------------------|---------| -| compliant | authorized | Fully valid - property in list, sold by authorized agent | -| compliant | unauthorized | Property is approved but sold by unauthorized reseller | -| non_compliant | authorized | Authorized agent sold property outside your list | -| non_compliant | unauthorized | Neither property nor agent validated | - -Both checks use the same "unknown excludes from rate" pattern - you cannot penalize for detection gaps. - -## Best Practices - -### Batch Validation - -For large-scale validation, batch records up to the 10,000 limit: - -```python -def validate_delivery_batch(records, list_id, governance_agent): - """Validate delivery records in batches.""" - batch_size = 10000 - all_results = [] - - for i in range(0, len(records), batch_size): - batch = records[i:i + batch_size] - response = governance_agent.validate_property_delivery( - list_id=list_id, - records=batch - ) - all_results.extend(response.results) - - return all_results -``` - -### Sampling Strategy - -For real-time monitoring during campaign execution, validate a statistical sample rather than all records: - -```python -import random - -def sample_and_validate(records, sample_size=1000): - """Validate a random sample for real-time monitoring.""" - sample = random.sample(records, min(sample_size, len(records))) - return governance_agent.validate_property_delivery( - list_id=list_id, - records=sample - ) -``` - -### Handling Unknown Records - -Track unknown rates separately to identify detection gaps: - -```python -def analyze_validation(response): - """Analyze validation results with unknown handling.""" - summary = response.summary - - # Core compliance metric - compliance_rate = summary.compliance_rate - - # Detection quality metric - unknown_rate = summary.unknown_impressions / summary.total_impressions - - if unknown_rate > 0.1: - print(f"Warning: {unknown_rate:.1%} of impressions unresolvable") - - return { - "compliance_rate": compliance_rate, - "unknown_rate": unknown_rate, - "non_compliant_impressions": summary.non_compliant_impressions - } -``` - -## Related Tasks - -- [create_property_list](/docs/governance/property/tasks/property_lists#create_property_list) - Create the list to validate against -- [get_property_list](/docs/governance/property/tasks/property_lists#get_property_list) - Retrieve current list membership -- [list_property_features](/docs/governance/property/tasks/list_property_features) - Discover available filter features diff --git a/v2.6-rc/docs/reference/media-channel-taxonomy.mdx b/v2.6-rc/docs/reference/media-channel-taxonomy.mdx deleted file mode 100644 index dbff98a547..0000000000 --- a/v2.6-rc/docs/reference/media-channel-taxonomy.mdx +++ /dev/null @@ -1,740 +0,0 @@ ---- -title: Media Channel Taxonomy -sidebar_position: 15 -description: A standardized taxonomy for advertising media channels, designed for interoperability across media planning tools, ad tech platforms, and AI agents. ---- - -# Media Channel Taxonomy - - -**Status**: Draft Specification -**Version**: 1.0.0-draft -**Last Updated**: 2026-01-23 - - -This specification defines a standardized taxonomy for advertising media channels. It is designed for interoperability across media planning tools, ad tech platforms, and AI-powered advertising agents. - -## Motivation - -The advertising industry lacks a standardized channel taxonomy. While IAB Tech Lab provides taxonomies for content, audience, and ad products, no equivalent exists for media channels. This leads to: - -- Inconsistent channel naming across platforms -- Difficulty aggregating cross-channel campaign data -- Confusion between channels, formats, and buying models -- Friction in automated media planning workflows - -This specification addresses these gaps by defining: - -1. **Media Channels** - How buyers allocate budget (planning abstractions) -2. **Property Types** - Addressable inventory surfaces with verifiable ownership -3. **Clear distinction** between channels, property types, and formats - -## Design Philosophy - -**Channels represent how buyers plan and allocate budget**, not where ads technically render. - -This is a deliberate design choice. Buyers don't say "I have $500K for web" — they say "I have $500K for display" or "I have $300K for OLV." The channel taxonomy reflects this reality. - -### Key Principles - -1. **Planning-oriented**: Channels match how agencies structure media plans -2. **Lightweight tags**: Channels help buyers express intent, not enforce precise classification -3. **Multi-channel support**: Properties may align with multiple channels (YouTube = `olv`, `social`, `ctv`) -4. **Publisher-declared**: Publishers indicate which channels their inventory supports -5. **Agent-reconciled**: Sales agents match buyer intent with publisher claims - -### Channels vs Technical Substrates - -Channels deliberately avoid substrate-level concepts like "web" or "mobile app" because: -- Buyers don't plan that way -- Most digital inventory would fall into both categories -- The same placement can be bought different ways - -Instead, channels describe **buying contexts**: display, OLV, social, search, CTV, etc. - -## Terminology - -The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119). - -## Definitions - -### Media Channel - -A **media channel** describes how buyers allocate budget. It represents a planning abstraction that encodes assumptions about audience, environment, and buying approach. - -Channels are defined by **buying context**, not by: -- Technical substrate (web vs app) -- How the ad looks (that's a **format**) -- The specific technology serving the ad - -### Property Type - -A **property type** describes a specific addressable inventory surface where: -- Ownership can be verified (e.g., via `adagents.json`) -- Ads can be programmatically served -- Identifiers exist for the property (domains, app IDs, device IDs) - -Property types are technical classifications, distinct from channels. The same property may support multiple channels. - -### Format Category - -A **format category** describes HOW an ad renders - its creative unit type. Examples: `video`, `audio`, `display`, `native`. Formats are orthogonal to channels. - -## Understanding Channels vs Property Types - -| Concept | Question It Answers | Determined By | Example | -|---------|---------------------|---------------|---------| -| **Channel** | How do buyers allocate budget? | Planning context | `retail_media` | -| **Property Type** | Where does the ad technically render? | Addressable inventory surface | `website` | - -### Why This Matters - -Consider retail media: when a buyer allocates budget to "retail media," they're buying: -1. Sponsored products on retailer websites -2. Display ads on retailer apps -3. Off-site ads using retailer data -4. In-store digital screens - -All of these are `retail_media` channel, but the property types vary (`website`, `mobile_app`, `dooh`). - -### Multi-Channel Properties - -Properties can align with multiple channels. Examples: - -| Property | Channels | Reasoning | -|----------|----------|-----------| -| YouTube | `olv`, `social`, `ctv` | Different buying contexts on same platform | -| ESPN App | `olv`, `display` | Supports video and display inventory | -| Amazon | `retail_media`, `search`, `display` | Multiple ad products | - -### When to Use Each - -**Use channel when:** -- Filtering products by budget allocation category -- Reporting on media mix -- Expressing buyer intent in product discovery - -**Use property_type when:** -- Validating inventory ownership via `adagents.json` -- Technical ad serving decisions -- Platform-specific targeting - -## Media Channels - -### Channel Enum - -The following 19 channels MUST be supported. Implementations MAY extend with additional channels using the `ext` field. - -| Channel | Description | -|---------|-------------| -| `display` | Digital display advertising (banners, native, rich media) | -| `olv` | Online video outside CTV (pre-roll, outstream, in-app video) | -| `social` | Social media platforms | -| `search` | Search engine advertising | -| `ctv` | Connected TV and streaming on television screens | -| `linear_tv` | Traditional broadcast and cable television | -| `radio` | Traditional AM/FM radio broadcast | -| `streaming_audio` | Digital audio streaming services | -| `podcast` | Podcast advertising | -| `dooh` | Digital out-of-home screens | -| `ooh` | Classic out-of-home (billboards, transit) | -| `print` | Newspapers, magazines, print publications | -| `cinema` | Movie theater advertising | -| `email` | Email advertising and newsletters | -| `gaming` | In-game advertising | -| `retail_media` | Retail media networks and commerce marketplaces | -| `influencer` | Creator and influencer partnerships | -| `affiliate` | Affiliate networks and performance-based partnerships | -| `product_placement` | Product placement and branded content | - -### Channel Definitions - -#### `display` - -Digital display advertising including banners, native units, and rich media across web and app environments. - -**Includes**: -- Display banners on websites -- Display ads in mobile apps -- Native content units -- Rich media ads -- Interstitials (non-video) - -**Excludes**: -- Video ads (use `olv` or `ctv`) -- Social platform ads (use `social`) -- Search results (use `search`) -- Retail media placements (use `retail_media`) - -**Typical Formats**: display, native, rich_media - -#### `olv` - -Online video advertising delivered outside of CTV/television environments. - -**Includes**: -- Pre-roll, mid-roll, post-roll on websites -- In-app video ads -- Outstream/in-feed video -- YouTube video ads (when not on TV screens) -- Video on news sites, sports sites, etc. - -**Excludes**: -- CTV/streaming on TV screens (use `ctv`) -- Social platform video (use `social`) -- Linear TV (use `linear_tv`) -- Retail media video (use `retail_media`) - -**Typical Formats**: video - -**Note**: OLV (Online Video) is a distinct planning bucket from CTV. Agencies commonly budget separately for "OLV" and "CTV" campaigns. - -#### `social` - -Social media platform advertising, regardless of technical delivery surface. - -**Includes**: -- Meta platforms (Facebook, Instagram, Threads) -- X (Twitter) -- TikTok -- LinkedIn -- Snapchat -- Pinterest -- Reddit -- YouTube (when bought through social-style targeting) - -**Excludes**: -- Influencer content on social platforms (use `influencer`) -- Video ads bought for reach, not social engagement (consider `olv`) - -**Typical Formats**: display, video, native - -**Note**: Social is defined by BUYING CONTEXT (social platform ad tools) and audience engagement model. - -#### `search` - -Search engine results pages and search advertising networks. - -**Includes**: -- Google Search ads -- Microsoft Bing ads -- DuckDuckGo ads -- App store search ads -- Shopping/product listing ads in search context - -**Excludes**: -- Display ads on search engine properties (use `display`) -- Retail media search (use `retail_media`) - -**Typical Formats**: text, display (shopping) - -#### `ctv` - -Connected TV advertising delivered through streaming applications on television screens. - -**Includes**: -- Streaming service apps (Netflix, Hulu, Max, etc.) -- Virtual MVPDs (YouTube TV, Sling, etc.) -- Free ad-supported streaming TV (FAST) -- Smart TV native apps -- Gaming console streaming apps - -**Excludes**: -- Linear broadcast/cable (use `linear_tv`) -- Video on phones/tablets/desktops (use `olv`) -- YouTube on mobile (use `olv` or `social`) - -**Typical Formats**: video - -#### `linear_tv` - -Traditional broadcast and cable television advertising. - -**Includes**: -- National broadcast networks (ABC, CBS, NBC, Fox) -- Cable networks (ESPN, CNN, HGTV) -- Local broadcast stations -- Addressable linear TV - -**Excludes**: -- Streaming on TV screens (use `ctv`) -- TV Everywhere apps on mobile (use `olv`) - -**Typical Formats**: video - -#### `radio` - -Traditional AM/FM radio broadcast advertising. - -**Includes**: -- Terrestrial radio stations -- Satellite radio (SiriusXM terrestrial simulcast) -- HD Radio - -**Excludes**: -- Streaming audio services (use `streaming_audio`) -- Podcasts (use `podcast`) - -**Typical Formats**: audio - -#### `streaming_audio` - -Digital audio streaming services. - -**Includes**: -- Music streaming (Spotify, Apple Music, Amazon Music, Pandora) -- Audio content platforms -- Digital radio streams (iHeartRadio digital, TuneIn) - -**Excludes**: -- Podcasts (use `podcast`) -- Terrestrial radio simulcast (use `radio`) - -**Typical Formats**: audio, display (companion) - -#### `podcast` - -Podcast advertising, including host-read and dynamically inserted ads. - -**Includes**: -- Host-read sponsorships -- Dynamically inserted audio ads -- Podcast network advertising - -**Excludes**: -- Music streaming (use `streaming_audio`) -- Video podcasts on YouTube (use `olv` or `social`) - -**Typical Formats**: audio - -#### `dooh` - -Digital out-of-home advertising on electronic screens in public spaces. - -**Includes**: -- Digital billboards -- Transit screens (subway, bus shelters, airports) -- Retail/mall digital displays -- Gas station screens -- Elevator screens -- Stadium/venue digital signage - -**Excludes**: -- Static billboards (use `ooh`) -- Cinema screens (use `cinema`) - -**Typical Formats**: display, video - -#### `ooh` - -Classic out-of-home advertising on physical (non-digital) surfaces. - -**Includes**: -- Static billboards -- Transit posters -- Street furniture -- Wallscapes -- Wild postings - -**Excludes**: -- Digital screens (use `dooh`) - -**Typical Formats**: display (static) - -#### `print` - -Newspaper, magazine, and other print publication advertising. - -**Includes**: -- Newspaper display ads -- Magazine display ads -- Newspaper/magazine inserts -- Trade publication advertising - -**Excludes**: -- Digital versions of publications (use `display`) -- Direct mail - -**Typical Formats**: display (static) - -#### `cinema` - -Movie theater advertising. - -**Includes**: -- Pre-show advertising -- On-screen trailers and ads -- Lobby displays -- Concession advertising - -**Excludes**: -- Streaming movie services (use `ctv`) - -**Typical Formats**: video, display - -#### `email` - -Email advertising and sponsored newsletter content. - -**Includes**: -- Sponsored email newsletters -- Email display advertising -- Dedicated email sends - -**Excludes**: -- Transactional email -- CRM/owned email marketing - -**Typical Formats**: display, native - -#### `gaming` - -In-game advertising across gaming platforms. - -**Includes**: -- In-game display ads -- Rewarded video ads -- Playable ads -- Advergames -- Esports sponsorships -- Gaming influencer integrations - -**Excludes**: -- Ads in non-gaming apps (use `display` or `olv`) -- Gaming content on streaming platforms (use `ctv` or `olv`) - -**Typical Formats**: display, video, native - -#### `retail_media` - -Retail media networks and commerce marketplace advertising. - -**Includes**: -- Retail media networks (Amazon Ads, Walmart Connect, Target Roundel) -- Grocery and delivery platforms (Instacart, DoorDash, Uber) -- Travel marketplaces (Expedia, Booking.com, Kayak) -- Financial services marketplaces -- Sponsored product listings -- On-site display and video on commerce platforms -- Off-site ads using retailer first-party data - -**Excludes**: -- General display ads (use `display`) -- Social commerce (use `social`) -- Search ads on non-commerce platforms (use `search`) - -**Typical Formats**: native, display, video - -**Note**: Retail media is distinguished by its transactional context and closed-loop attribution capabilities. - -#### `influencer` - -Creator and influencer marketing partnerships. - -**Includes**: -- Sponsored content creation -- Brand ambassador programs -- Affiliate creator partnerships -- User-generated content campaigns - -**Excludes**: -- Ads placed on creator content by platforms (use `social`) -- Podcast host reads (use `podcast`) - -**Typical Formats**: video, native, display - -**Note**: `influencer` describes the BUYING MODEL (creator partnership) rather than where content appears. - -#### `affiliate` - -Affiliate networks, comparison sites, and performance-based publisher partnerships. - -**Includes**: -- Affiliate networks (CJ, Rakuten, Impact, Awin, ShareASale) -- Comparison shopping engines (NerdWallet, Bankrate, The Points Guy) -- Review and recommendation sites -- Coupon and deal sites (RetailMeNot, Honey) -- Content commerce (editorial with affiliate links) -- Lead generation sites -- Cashback and loyalty programs - -**Excludes**: -- Standard display ads on affiliate sites (use `display`) -- Influencer partnerships (use `influencer`) -- Retail media sponsored products (use `retail_media`) - -**Typical Formats**: native, display, text - -**Note**: `affiliate` describes the BUYING MODEL (performance-based, CPA/CPC/rev-share) rather than where content appears. - -#### `product_placement` - -Product placement, branded content, and sponsorship integrations. - -**Includes**: -- Traditional product placement (film, TV) -- Virtual product placement -- Branded entertainment -- Event sponsorships -- Naming rights -- Branded content series - -**Excludes**: -- Influencer partnerships (use `influencer`) -- Standard ad placements at sponsored events (use appropriate channel) - -**Typical Formats**: native, video - -## Property Types - -Property types describe addressable inventory surfaces with verifiable ownership. They are used in `adagents.json` for authorization validation. - -### Property Type Enum - -| Property Type | Description | Example Channels | -|---------------|-------------|------------------| -| `website` | Web properties accessible via browser | `display`, `olv` | -| `mobile_app` | Native mobile applications | `display`, `olv`, `social`, `gaming` | -| `ctv_app` | Connected TV applications | `ctv` | -| `desktop_app` | Desktop applications (Electron, native) | `streaming_audio`, `gaming` | -| `dooh` | Digital out-of-home screen networks | `dooh` | -| `podcast` | Podcast feeds and episodes | `podcast` | -| `radio` | Radio station properties | `radio` | -| `streaming_audio` | Digital audio streaming properties | `streaming_audio` | - -### Channels Without Property Types - -The following channels do not have corresponding property types because they lack addressable, verifiable inventory surfaces in the traditional sense: - -- `linear_tv` - Broadcast/cable inventory is managed through different authorization mechanisms -- `ooh` - Physical inventory lacks digital identifiers -- `print` - Physical publication inventory -- `cinema` - Theater inventory management systems -- `email` - Email list ownership differs from property authorization -- `influencer` - Creator relationships rather than property ownership -- `affiliate` - Performance-based partnerships, placements appear on partner websites -- `product_placement` - Content/event relationships rather than properties -- `retail_media` - Platform-managed inventory within retail ecosystems -- `search` - Platform-managed inventory -- `social` - Platform-managed inventory - -## Relationship Between Concepts - -``` -┌─────────────────────────────────────────────────────────────────┐ -│ MEDIA CHANNEL │ -│ How buyers allocate budget (planning abstraction) │ -│ │ -│ display, olv, social, search, ctv, linear_tv, podcast, │ -│ streaming_audio, radio, dooh, ooh, print, cinema, email, │ -│ gaming, retail_media, influencer, affiliate, product_placement│ -└─────────────────────────────────────────────────────────────────┘ - -┌─────────────────────────────────────────────────────────────────┐ -│ PROPERTY TYPE │ -│ Addressable inventory with verifiable ownership (technical) │ -│ │ -│ website, mobile_app, ctv_app, desktop_app, dooh, │ -│ podcast, radio, streaming_audio │ -└─────────────────────────────────────────────────────────────────┘ - -┌─────────────────────────────────────────────────────────────────┐ -│ FORMAT CATEGORY │ -│ How the ad renders (orthogonal to channel) │ -│ │ -│ audio, video, display, native, rich_media, text │ -└─────────────────────────────────────────────────────────────────┘ -``` - -## Implementation - -### JSON Schema - -Channels are defined in the AdCP schema at: - -``` -/schemas/v1/enums/channels.json -``` - -```json -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "/schemas/enums/channels.json", - "title": "Media Channel", - "description": "Standardized advertising media channels describing how buyers allocate budget", - "type": "string", - "enum": [ - "display", - "olv", - "social", - "search", - "ctv", - "linear_tv", - "radio", - "streaming_audio", - "podcast", - "dooh", - "ooh", - "print", - "cinema", - "email", - "gaming", - "retail_media", - "influencer", - "affiliate", - "product_placement" - ] -} -``` - -### Usage in Product Discovery - -When filtering products by channel: - -```json -{ - "filters": { - "channels": ["ctv", "olv", "streaming_audio"] - } -} -``` - -### Usage in Property Definitions - -Properties in `adagents.json` declare which channels they support: - -```json -{ - "properties": [ - { - "property_id": "youtube_app", - "property_type": "ctv_app", - "name": "YouTube CTV", - "supported_channels": ["ctv", "olv", "social"], - "identifiers": [ - {"type": "roku_store_id", "value": "12345"} - ] - } - ] -} -``` - -### Extensibility - -Implementations MAY support additional channels beyond this specification using the `ext` field pattern: - -```json -{ - "channel": "display", - "ext": { - "sub_channel": "native_content" - } -} -``` - -## Versioning - -This taxonomy follows [Semantic Versioning](https://semver.org/): - -- **MAJOR**: Removing channels, changing channel semantics -- **MINOR**: Adding new channels (append-only) -- **PATCH**: Clarifying descriptions, fixing typos - -Adding new channels is a MINOR version change and MUST NOT break existing implementations. - -## Migration from Legacy Channel Values - -Prior to this taxonomy, AdCP used a different set of channel values. The following table maps legacy values to the new taxonomy: - -| Legacy Value | New Channel(s) | Notes | -|--------------|----------------|-------| -| `display` | `display` | No change, but now excludes video | -| `video` | `olv`, `ctv` | Split by viewing environment | -| `audio` | `streaming_audio`, `podcast`, `radio` | Split by audio type | -| `native` | `display` | Native is a format, not a channel | -| `web` | `display`, `olv` | Web is a substrate, not a planning bucket | -| `mobile_app` | `display`, `olv`, `gaming` | App is a substrate, not a planning bucket | -| `dooh` | `dooh` | No change | -| `ctv` | `ctv` | No change | -| `podcast` | `podcast` | No change | -| `retail` | `retail_media` | Renamed | -| `commerce_media` | `retail_media` | Renamed | -| `social` | `social` | No change | -| `sponsorship` | `product_placement` | Renamed and refined | - -### Migration Guidance - -1. **Identify the planning context**: Determine HOW the buyer allocates budget, not where ads technically render. - -2. **Split video by environment**: If video was a single category, split into `olv` (desktop/mobile) and `ctv` (TV screens). - -3. **Remove substrate channels**: If you had `web` or `mobile_app` as channels, map to planning-oriented channels (`display`, `olv`) based on buying context. - -4. **Update filters**: When filtering products, use the new channel values. - -## Edge Cases and Ambiguities - -### YouTube Classification - -YouTube spans multiple channels depending on context: - -| Scenario | Channel | Reasoning | -|----------|---------|-----------| -| YouTube video ad on phone/desktop | `olv` or `social` | Depends on buying approach | -| YouTube video ad on CTV | `ctv` | TV screen environment | -| YouTube Shorts | `social` | Short-form social context | -| YouTube Music | `streaming_audio` | Audio streaming context | - -### Retail Media Complexity - -Retail media may eventually warrant sub-channels: - -| Scenario | Current | Potential Future | -|----------|---------|------------------| -| Sponsored products on Amazon | `retail_media` | `retail_media_search` | -| Display on retailer site | `retail_media` | `retail_media_display` | -| Off-site using retailer data | `retail_media` | `retail_media_offsite` | - -For now, use `retail_media` with format filters to distinguish. - -### Gaming vs Display/OLV - -| Scenario | Channel | Reasoning | -|----------|---------|-----------| -| Rewarded video in mobile game via Unity Ads | `gaming` | Gaming-specific ad network | -| Banner in casual game via AdMob general pool | `display` | Standard mobile programmatic | -| Esports tournament sponsorship | `gaming` | Gaming audience context | - -### Influencer vs Social - -| Scenario | Channel | Reasoning | -|----------|---------|-----------| -| Buying promoted posts through Instagram Ads | `social` | Platform ad tools | -| Contracting an influencer directly | `influencer` | Creator partnership | -| Platform-inserted ads around creator content | `social` | Platform ad tools | - -## Future Considerations - -The following channels may be added in future versions based on market evolution: - -- `messaging` - WhatsApp Business, Telegram ads -- `xr` - VR/AR advertising -- `ai_agents` - AI assistant and chatbot advertising - -## References - -- [IAB Tech Lab Taxonomies](https://github.com/InteractiveAdvertisingBureau/Taxonomies) - Content, Audience, Ad Product -- [OpenRTB/AdCOM](https://github.com/InteractiveAdvertisingBureau/AdCOM) - Placement types and media objects -- [Planmatic Media Plan Schema](https://github.com/planmatic/mediaplanschema) - Media planning data structures -- [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119) - Requirement level keywords - -## Changelog - -### 1.0.0-draft (2026-01-23) - -- Initial draft specification -- 19 channels defined (planning-oriented approach) -- 8 property types defined -- Clear distinction between channel (planning abstraction), property_type (technical surface), and format -- Multi-channel support for properties -- Migration guide from legacy values From 9a259ce4f60dd6274f8f3049d666403abda5a687 Mon Sep 17 00:00:00 2001 From: Brian O'Kelley Date: Sat, 24 Jan 2026 11:57:07 -0500 Subject: [PATCH 32/34] chore: bump version to 3.0.0-beta.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Breaking changes require major version bump: - package.json: 2.6.0 → 3.0.0-beta.1 - schema registry: adcp_version 2.6.0 → 3.0.0-beta.1 - docs.json: version label 2.6 → 3.0-beta - dist/schemas: renamed 2.6.0 → 3.0.0-beta.1 Co-Authored-By: Claude Opus 4.5 --- dist/schemas/{2.6.0 => 3.0.0-beta.1}/adagents.json | 0 .../bundled/media-buy/build-creative-request.json | 0 .../bundled/media-buy/build-creative-response.json | 0 .../bundled/media-buy/create-media-buy-request.json | 0 .../bundled/media-buy/create-media-buy-response.json | 0 .../bundled/media-buy/get-media-buy-delivery-request.json | 0 .../bundled/media-buy/get-media-buy-delivery-response.json | 0 .../bundled/media-buy/get-products-request.json | 0 .../bundled/media-buy/get-products-response.json | 0 .../bundled/media-buy/list-authorized-properties-request.json | 0 .../bundled/media-buy/list-authorized-properties-response.json | 0 .../bundled/media-buy/list-creative-formats-request.json | 0 .../bundled/media-buy/list-creative-formats-response.json | 0 .../bundled/media-buy/list-creatives-request.json | 0 .../bundled/media-buy/list-creatives-response.json | 0 .../bundled/media-buy/package-request.json | 0 .../bundled/media-buy/provide-performance-feedback-request.json | 0 .../media-buy/provide-performance-feedback-response.json | 0 .../bundled/media-buy/sync-creatives-request.json | 0 .../bundled/media-buy/sync-creatives-response.json | 0 .../bundled/media-buy/update-media-buy-request.json | 0 .../bundled/media-buy/update-media-buy-response.json | 0 .../bundled/signals/activate-signal-request.json | 0 .../bundled/signals/activate-signal-response.json | 0 .../bundled/signals/get-signals-request.json | 0 .../bundled/signals/get-signals-response.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/activation-key.json | 0 .../{2.6.0 => 3.0.0-beta.1}/core/assets/audio-asset.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/assets/css-asset.json | 0 .../{2.6.0 => 3.0.0-beta.1}/core/assets/daast-asset.json | 0 .../schemas/{2.6.0 => 3.0.0-beta.1}/core/assets/html-asset.json | 0 .../{2.6.0 => 3.0.0-beta.1}/core/assets/image-asset.json | 0 .../{2.6.0 => 3.0.0-beta.1}/core/assets/javascript-asset.json | 0 .../{2.6.0 => 3.0.0-beta.1}/core/assets/markdown-asset.json | 0 .../schemas/{2.6.0 => 3.0.0-beta.1}/core/assets/text-asset.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/assets/url-asset.json | 0 .../schemas/{2.6.0 => 3.0.0-beta.1}/core/assets/vast-asset.json | 0 .../{2.6.0 => 3.0.0-beta.1}/core/assets/video-asset.json | 0 .../{2.6.0 => 3.0.0-beta.1}/core/assets/webhook-asset.json | 0 .../{2.6.0 => 3.0.0-beta.1}/core/async-response-data.json | 0 .../{2.6.0 => 3.0.0-beta.1}/core/brand-manifest-ref.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/brand-manifest.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/context.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/creative-asset.json | 0 .../{2.6.0 => 3.0.0-beta.1}/core/creative-assignment.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/creative-filters.json | 0 .../schemas/{2.6.0 => 3.0.0-beta.1}/core/creative-manifest.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/creative-policy.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/delivery-metrics.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/deployment.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/destination.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/error.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/ext.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/format-id.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/format.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/frequency-cap.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/identifier.json | 0 .../{2.6.0 => 3.0.0-beta.1}/core/mcp-webhook-payload.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/measurement.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/media-buy.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/package.json | 0 .../{2.6.0 => 3.0.0-beta.1}/core/performance-feedback.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/placement.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/pricing-option.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/product-filters.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/product.json | 0 .../{2.6.0 => 3.0.0-beta.1}/core/promoted-offerings.json | 0 .../schemas/{2.6.0 => 3.0.0-beta.1}/core/promoted-products.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/property-id.json | 0 .../schemas/{2.6.0 => 3.0.0-beta.1}/core/property-list-ref.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/property-tag.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/property.json | 0 .../schemas/{2.6.0 => 3.0.0-beta.1}/core/protocol-envelope.json | 0 .../core/publisher-property-selector.json | 0 .../{2.6.0 => 3.0.0-beta.1}/core/push-notification-config.json | 0 .../{2.6.0 => 3.0.0-beta.1}/core/reporting-capabilities.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/response.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/signal-filters.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/start-timing.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/sub-asset.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/targeting.json | 0 .../schemas/{2.6.0 => 3.0.0-beta.1}/core/tasks-get-request.json | 0 .../{2.6.0 => 3.0.0-beta.1}/core/tasks-get-response.json | 0 .../{2.6.0 => 3.0.0-beta.1}/core/tasks-list-request.json | 0 .../{2.6.0 => 3.0.0-beta.1}/core/tasks-list-response.json | 0 .../{2.6.0 => 3.0.0-beta.1}/creative/asset-types/index.json | 0 .../creative/list-creative-formats-request.json | 0 .../creative/list-creative-formats-response.json | 0 .../creative/preview-creative-request.json | 0 .../creative/preview-creative-response.json | 0 .../{2.6.0 => 3.0.0-beta.1}/creative/preview-render.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/adcp-domain.json | 0 .../{2.6.0 => 3.0.0-beta.1}/enums/asset-content-type.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/auth-scheme.json | 0 .../schemas/{2.6.0 => 3.0.0-beta.1}/enums/available-metric.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/channels.json | 0 .../{2.6.0 => 3.0.0-beta.1}/enums/co-branding-requirement.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/creative-action.json | 0 .../enums/creative-agent-capability.json | 0 .../{2.6.0 => 3.0.0-beta.1}/enums/creative-sort-field.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/creative-status.json | 0 .../{2.6.0 => 3.0.0-beta.1}/enums/daast-tracking-event.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/daast-version.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/delivery-type.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/dimension-unit.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/feed-format.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/feedback-source.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/format-category.json | 0 .../{2.6.0 => 3.0.0-beta.1}/enums/format-id-parameter.json | 0 .../{2.6.0 => 3.0.0-beta.1}/enums/frequency-cap-scope.json | 0 .../{2.6.0 => 3.0.0-beta.1}/enums/history-entry-type.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/http-method.json | 0 .../schemas/{2.6.0 => 3.0.0-beta.1}/enums/identifier-types.json | 0 .../{2.6.0 => 3.0.0-beta.1}/enums/javascript-module-type.json | 0 .../{2.6.0 => 3.0.0-beta.1}/enums/landing-page-requirement.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/markdown-flavor.json | 0 .../schemas/{2.6.0 => 3.0.0-beta.1}/enums/media-buy-status.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/metric-type.json | 0 .../{2.6.0 => 3.0.0-beta.1}/enums/notification-type.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/pacing.json | 0 .../{2.6.0 => 3.0.0-beta.1}/enums/preview-output-format.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/pricing-model.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/property-type.json | 0 .../enums/publisher-identifier-types.json | 0 .../{2.6.0 => 3.0.0-beta.1}/enums/reporting-frequency.json | 0 .../{2.6.0 => 3.0.0-beta.1}/enums/signal-catalog-type.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/sort-direction.json | 0 .../{2.6.0 => 3.0.0-beta.1}/enums/standard-format-ids.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/task-status.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/task-type.json | 0 .../schemas/{2.6.0 => 3.0.0-beta.1}/enums/update-frequency.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/url-asset-type.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/validation-mode.json | 0 .../{2.6.0 => 3.0.0-beta.1}/enums/vast-tracking-event.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/vast-version.json | 0 .../{2.6.0 => 3.0.0-beta.1}/enums/webhook-response-type.json | 0 .../{2.6.0 => 3.0.0-beta.1}/enums/webhook-security-method.json | 0 .../{2.6.0 => 3.0.0-beta.1}/extensions/extension-meta.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/extensions/index.json | 0 dist/schemas/{2.6.0 => 3.0.0-beta.1}/index.json | 0 .../media-buy/build-creative-request.json | 0 .../media-buy/build-creative-response.json | 0 .../create-media-buy-async-response-input-required.json | 0 .../media-buy/create-media-buy-async-response-submitted.json | 0 .../media-buy/create-media-buy-async-response-working.json | 0 .../media-buy/create-media-buy-request.json | 0 .../media-buy/create-media-buy-response.json | 0 .../media-buy/get-media-buy-delivery-request.json | 0 .../media-buy/get-media-buy-delivery-response.json | 0 .../media-buy/get-products-async-response-input-required.json | 0 .../media-buy/get-products-async-response-submitted.json | 0 .../media-buy/get-products-async-response-working.json | 0 .../{2.6.0 => 3.0.0-beta.1}/media-buy/get-products-request.json | 0 .../media-buy/get-products-response.json | 0 .../media-buy/list-authorized-properties-request.json | 0 .../media-buy/list-authorized-properties-response.json | 0 .../media-buy/list-creative-formats-request.json | 0 .../media-buy/list-creative-formats-response.json | 0 .../media-buy/list-creatives-request.json | 0 .../media-buy/list-creatives-response.json | 0 .../{2.6.0 => 3.0.0-beta.1}/media-buy/package-request.json | 0 .../media-buy/provide-performance-feedback-request.json | 0 .../media-buy/provide-performance-feedback-response.json | 0 .../media-buy/sync-creatives-async-response-input-required.json | 0 .../media-buy/sync-creatives-async-response-submitted.json | 0 .../media-buy/sync-creatives-async-response-working.json | 0 .../media-buy/sync-creatives-request.json | 0 .../media-buy/sync-creatives-response.json | 0 .../update-media-buy-async-response-input-required.json | 0 .../media-buy/update-media-buy-async-response-submitted.json | 0 .../media-buy/update-media-buy-async-response-working.json | 0 .../media-buy/update-media-buy-request.json | 0 .../media-buy/update-media-buy-response.json | 0 .../{2.6.0 => 3.0.0-beta.1}/pricing-options/cpc-option.json | 0 .../{2.6.0 => 3.0.0-beta.1}/pricing-options/cpcv-option.json | 0 .../pricing-options/cpm-auction-option.json | 0 .../pricing-options/cpm-fixed-option.json | 0 .../{2.6.0 => 3.0.0-beta.1}/pricing-options/cpp-option.json | 0 .../{2.6.0 => 3.0.0-beta.1}/pricing-options/cpv-option.json | 0 .../pricing-options/flat-rate-option.json | 0 .../pricing-options/vcpm-auction-option.json | 0 .../pricing-options/vcpm-fixed-option.json | 0 .../{2.6.0 => 3.0.0-beta.1}/property/authorization-result.json | 0 .../{2.6.0 => 3.0.0-beta.1}/property/base-property-source.json | 0 .../property/create-property-list-request.json | 0 .../property/create-property-list-response.json | 0 .../property/delete-property-list-request.json | 0 .../property/delete-property-list-response.json | 0 .../{2.6.0 => 3.0.0-beta.1}/property/delivery-record.json | 0 .../{2.6.0 => 3.0.0-beta.1}/property/feature-requirement.json | 0 .../property/get-property-features-request.json | 0 .../property/get-property-features-response.json | 0 .../property/get-property-list-request.json | 0 .../property/get-property-list-response.json | 0 .../property/list-property-features-request.json | 0 .../property/list-property-features-response.json | 0 .../property/list-property-lists-request.json | 0 .../property/list-property-lists-response.json | 0 .../{2.6.0 => 3.0.0-beta.1}/property/property-error.json | 0 .../property/property-feature-definition.json | 0 .../property/property-feature-result.json | 0 .../property/property-feature-value.json | 0 .../{2.6.0 => 3.0.0-beta.1}/property/property-feature.json | 0 .../property/property-list-changed-webhook.json | 0 .../{2.6.0 => 3.0.0-beta.1}/property/property-list-filters.json | 0 .../schemas/{2.6.0 => 3.0.0-beta.1}/property/property-list.json | 0 .../property/update-property-list-request.json | 0 .../property/update-property-list-response.json | 0 .../property/validate-property-delivery-request.json | 0 .../property/validate-property-delivery-response.json | 0 .../{2.6.0 => 3.0.0-beta.1}/property/validation-result.json | 0 .../{2.6.0 => 3.0.0-beta.1}/protocols/adcp-extension.json | 0 .../signals/activate-signal-request.json | 0 .../signals/activate-signal-response.json | 0 .../{2.6.0 => 3.0.0-beta.1}/signals/get-signals-request.json | 0 .../{2.6.0 => 3.0.0-beta.1}/signals/get-signals-response.json | 0 docs.json | 2 +- package.json | 2 +- static/schemas/source/index.json | 2 +- 219 files changed, 3 insertions(+), 3 deletions(-) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/adagents.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/bundled/media-buy/build-creative-request.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/bundled/media-buy/build-creative-response.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/bundled/media-buy/create-media-buy-request.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/bundled/media-buy/create-media-buy-response.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/bundled/media-buy/get-media-buy-delivery-request.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/bundled/media-buy/get-media-buy-delivery-response.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/bundled/media-buy/get-products-request.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/bundled/media-buy/get-products-response.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/bundled/media-buy/list-authorized-properties-request.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/bundled/media-buy/list-authorized-properties-response.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/bundled/media-buy/list-creative-formats-request.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/bundled/media-buy/list-creative-formats-response.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/bundled/media-buy/list-creatives-request.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/bundled/media-buy/list-creatives-response.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/bundled/media-buy/package-request.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/bundled/media-buy/provide-performance-feedback-request.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/bundled/media-buy/provide-performance-feedback-response.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/bundled/media-buy/sync-creatives-request.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/bundled/media-buy/sync-creatives-response.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/bundled/media-buy/update-media-buy-request.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/bundled/media-buy/update-media-buy-response.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/bundled/signals/activate-signal-request.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/bundled/signals/activate-signal-response.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/bundled/signals/get-signals-request.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/bundled/signals/get-signals-response.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/activation-key.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/assets/audio-asset.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/assets/css-asset.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/assets/daast-asset.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/assets/html-asset.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/assets/image-asset.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/assets/javascript-asset.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/assets/markdown-asset.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/assets/text-asset.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/assets/url-asset.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/assets/vast-asset.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/assets/video-asset.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/assets/webhook-asset.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/async-response-data.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/brand-manifest-ref.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/brand-manifest.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/context.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/creative-asset.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/creative-assignment.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/creative-filters.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/creative-manifest.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/creative-policy.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/delivery-metrics.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/deployment.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/destination.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/error.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/ext.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/format-id.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/format.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/frequency-cap.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/identifier.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/mcp-webhook-payload.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/measurement.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/media-buy.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/package.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/performance-feedback.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/placement.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/pricing-option.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/product-filters.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/product.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/promoted-offerings.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/promoted-products.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/property-id.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/property-list-ref.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/property-tag.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/property.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/protocol-envelope.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/publisher-property-selector.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/push-notification-config.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/reporting-capabilities.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/response.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/signal-filters.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/start-timing.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/sub-asset.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/targeting.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/tasks-get-request.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/tasks-get-response.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/tasks-list-request.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/core/tasks-list-response.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/creative/asset-types/index.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/creative/list-creative-formats-request.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/creative/list-creative-formats-response.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/creative/preview-creative-request.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/creative/preview-creative-response.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/creative/preview-render.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/adcp-domain.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/asset-content-type.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/auth-scheme.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/available-metric.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/channels.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/co-branding-requirement.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/creative-action.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/creative-agent-capability.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/creative-sort-field.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/creative-status.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/daast-tracking-event.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/daast-version.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/delivery-type.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/dimension-unit.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/feed-format.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/feedback-source.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/format-category.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/format-id-parameter.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/frequency-cap-scope.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/history-entry-type.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/http-method.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/identifier-types.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/javascript-module-type.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/landing-page-requirement.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/markdown-flavor.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/media-buy-status.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/metric-type.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/notification-type.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/pacing.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/preview-output-format.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/pricing-model.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/property-type.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/publisher-identifier-types.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/reporting-frequency.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/signal-catalog-type.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/sort-direction.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/standard-format-ids.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/task-status.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/task-type.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/update-frequency.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/url-asset-type.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/validation-mode.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/vast-tracking-event.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/vast-version.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/webhook-response-type.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/enums/webhook-security-method.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/extensions/extension-meta.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/extensions/index.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/index.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/media-buy/build-creative-request.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/media-buy/build-creative-response.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/media-buy/create-media-buy-async-response-input-required.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/media-buy/create-media-buy-async-response-submitted.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/media-buy/create-media-buy-async-response-working.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/media-buy/create-media-buy-request.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/media-buy/create-media-buy-response.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/media-buy/get-media-buy-delivery-request.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/media-buy/get-media-buy-delivery-response.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/media-buy/get-products-async-response-input-required.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/media-buy/get-products-async-response-submitted.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/media-buy/get-products-async-response-working.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/media-buy/get-products-request.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/media-buy/get-products-response.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/media-buy/list-authorized-properties-request.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/media-buy/list-authorized-properties-response.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/media-buy/list-creative-formats-request.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/media-buy/list-creative-formats-response.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/media-buy/list-creatives-request.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/media-buy/list-creatives-response.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/media-buy/package-request.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/media-buy/provide-performance-feedback-request.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/media-buy/provide-performance-feedback-response.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/media-buy/sync-creatives-async-response-input-required.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/media-buy/sync-creatives-async-response-submitted.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/media-buy/sync-creatives-async-response-working.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/media-buy/sync-creatives-request.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/media-buy/sync-creatives-response.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/media-buy/update-media-buy-async-response-input-required.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/media-buy/update-media-buy-async-response-submitted.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/media-buy/update-media-buy-async-response-working.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/media-buy/update-media-buy-request.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/media-buy/update-media-buy-response.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/pricing-options/cpc-option.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/pricing-options/cpcv-option.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/pricing-options/cpm-auction-option.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/pricing-options/cpm-fixed-option.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/pricing-options/cpp-option.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/pricing-options/cpv-option.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/pricing-options/flat-rate-option.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/pricing-options/vcpm-auction-option.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/pricing-options/vcpm-fixed-option.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/property/authorization-result.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/property/base-property-source.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/property/create-property-list-request.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/property/create-property-list-response.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/property/delete-property-list-request.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/property/delete-property-list-response.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/property/delivery-record.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/property/feature-requirement.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/property/get-property-features-request.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/property/get-property-features-response.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/property/get-property-list-request.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/property/get-property-list-response.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/property/list-property-features-request.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/property/list-property-features-response.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/property/list-property-lists-request.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/property/list-property-lists-response.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/property/property-error.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/property/property-feature-definition.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/property/property-feature-result.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/property/property-feature-value.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/property/property-feature.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/property/property-list-changed-webhook.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/property/property-list-filters.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/property/property-list.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/property/update-property-list-request.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/property/update-property-list-response.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/property/validate-property-delivery-request.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/property/validate-property-delivery-response.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/property/validation-result.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/protocols/adcp-extension.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/signals/activate-signal-request.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/signals/activate-signal-response.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/signals/get-signals-request.json (100%) rename dist/schemas/{2.6.0 => 3.0.0-beta.1}/signals/get-signals-response.json (100%) diff --git a/dist/schemas/2.6.0/adagents.json b/dist/schemas/3.0.0-beta.1/adagents.json similarity index 100% rename from dist/schemas/2.6.0/adagents.json rename to dist/schemas/3.0.0-beta.1/adagents.json diff --git a/dist/schemas/2.6.0/bundled/media-buy/build-creative-request.json b/dist/schemas/3.0.0-beta.1/bundled/media-buy/build-creative-request.json similarity index 100% rename from dist/schemas/2.6.0/bundled/media-buy/build-creative-request.json rename to dist/schemas/3.0.0-beta.1/bundled/media-buy/build-creative-request.json diff --git a/dist/schemas/2.6.0/bundled/media-buy/build-creative-response.json b/dist/schemas/3.0.0-beta.1/bundled/media-buy/build-creative-response.json similarity index 100% rename from dist/schemas/2.6.0/bundled/media-buy/build-creative-response.json rename to dist/schemas/3.0.0-beta.1/bundled/media-buy/build-creative-response.json diff --git a/dist/schemas/2.6.0/bundled/media-buy/create-media-buy-request.json b/dist/schemas/3.0.0-beta.1/bundled/media-buy/create-media-buy-request.json similarity index 100% rename from dist/schemas/2.6.0/bundled/media-buy/create-media-buy-request.json rename to dist/schemas/3.0.0-beta.1/bundled/media-buy/create-media-buy-request.json diff --git a/dist/schemas/2.6.0/bundled/media-buy/create-media-buy-response.json b/dist/schemas/3.0.0-beta.1/bundled/media-buy/create-media-buy-response.json similarity index 100% rename from dist/schemas/2.6.0/bundled/media-buy/create-media-buy-response.json rename to dist/schemas/3.0.0-beta.1/bundled/media-buy/create-media-buy-response.json diff --git a/dist/schemas/2.6.0/bundled/media-buy/get-media-buy-delivery-request.json b/dist/schemas/3.0.0-beta.1/bundled/media-buy/get-media-buy-delivery-request.json similarity index 100% rename from dist/schemas/2.6.0/bundled/media-buy/get-media-buy-delivery-request.json rename to dist/schemas/3.0.0-beta.1/bundled/media-buy/get-media-buy-delivery-request.json diff --git a/dist/schemas/2.6.0/bundled/media-buy/get-media-buy-delivery-response.json b/dist/schemas/3.0.0-beta.1/bundled/media-buy/get-media-buy-delivery-response.json similarity index 100% rename from dist/schemas/2.6.0/bundled/media-buy/get-media-buy-delivery-response.json rename to dist/schemas/3.0.0-beta.1/bundled/media-buy/get-media-buy-delivery-response.json diff --git a/dist/schemas/2.6.0/bundled/media-buy/get-products-request.json b/dist/schemas/3.0.0-beta.1/bundled/media-buy/get-products-request.json similarity index 100% rename from dist/schemas/2.6.0/bundled/media-buy/get-products-request.json rename to dist/schemas/3.0.0-beta.1/bundled/media-buy/get-products-request.json diff --git a/dist/schemas/2.6.0/bundled/media-buy/get-products-response.json b/dist/schemas/3.0.0-beta.1/bundled/media-buy/get-products-response.json similarity index 100% rename from dist/schemas/2.6.0/bundled/media-buy/get-products-response.json rename to dist/schemas/3.0.0-beta.1/bundled/media-buy/get-products-response.json diff --git a/dist/schemas/2.6.0/bundled/media-buy/list-authorized-properties-request.json b/dist/schemas/3.0.0-beta.1/bundled/media-buy/list-authorized-properties-request.json similarity index 100% rename from dist/schemas/2.6.0/bundled/media-buy/list-authorized-properties-request.json rename to dist/schemas/3.0.0-beta.1/bundled/media-buy/list-authorized-properties-request.json diff --git a/dist/schemas/2.6.0/bundled/media-buy/list-authorized-properties-response.json b/dist/schemas/3.0.0-beta.1/bundled/media-buy/list-authorized-properties-response.json similarity index 100% rename from dist/schemas/2.6.0/bundled/media-buy/list-authorized-properties-response.json rename to dist/schemas/3.0.0-beta.1/bundled/media-buy/list-authorized-properties-response.json diff --git a/dist/schemas/2.6.0/bundled/media-buy/list-creative-formats-request.json b/dist/schemas/3.0.0-beta.1/bundled/media-buy/list-creative-formats-request.json similarity index 100% rename from dist/schemas/2.6.0/bundled/media-buy/list-creative-formats-request.json rename to dist/schemas/3.0.0-beta.1/bundled/media-buy/list-creative-formats-request.json diff --git a/dist/schemas/2.6.0/bundled/media-buy/list-creative-formats-response.json b/dist/schemas/3.0.0-beta.1/bundled/media-buy/list-creative-formats-response.json similarity index 100% rename from dist/schemas/2.6.0/bundled/media-buy/list-creative-formats-response.json rename to dist/schemas/3.0.0-beta.1/bundled/media-buy/list-creative-formats-response.json diff --git a/dist/schemas/2.6.0/bundled/media-buy/list-creatives-request.json b/dist/schemas/3.0.0-beta.1/bundled/media-buy/list-creatives-request.json similarity index 100% rename from dist/schemas/2.6.0/bundled/media-buy/list-creatives-request.json rename to dist/schemas/3.0.0-beta.1/bundled/media-buy/list-creatives-request.json diff --git a/dist/schemas/2.6.0/bundled/media-buy/list-creatives-response.json b/dist/schemas/3.0.0-beta.1/bundled/media-buy/list-creatives-response.json similarity index 100% rename from dist/schemas/2.6.0/bundled/media-buy/list-creatives-response.json rename to dist/schemas/3.0.0-beta.1/bundled/media-buy/list-creatives-response.json diff --git a/dist/schemas/2.6.0/bundled/media-buy/package-request.json b/dist/schemas/3.0.0-beta.1/bundled/media-buy/package-request.json similarity index 100% rename from dist/schemas/2.6.0/bundled/media-buy/package-request.json rename to dist/schemas/3.0.0-beta.1/bundled/media-buy/package-request.json diff --git a/dist/schemas/2.6.0/bundled/media-buy/provide-performance-feedback-request.json b/dist/schemas/3.0.0-beta.1/bundled/media-buy/provide-performance-feedback-request.json similarity index 100% rename from dist/schemas/2.6.0/bundled/media-buy/provide-performance-feedback-request.json rename to dist/schemas/3.0.0-beta.1/bundled/media-buy/provide-performance-feedback-request.json diff --git a/dist/schemas/2.6.0/bundled/media-buy/provide-performance-feedback-response.json b/dist/schemas/3.0.0-beta.1/bundled/media-buy/provide-performance-feedback-response.json similarity index 100% rename from dist/schemas/2.6.0/bundled/media-buy/provide-performance-feedback-response.json rename to dist/schemas/3.0.0-beta.1/bundled/media-buy/provide-performance-feedback-response.json diff --git a/dist/schemas/2.6.0/bundled/media-buy/sync-creatives-request.json b/dist/schemas/3.0.0-beta.1/bundled/media-buy/sync-creatives-request.json similarity index 100% rename from dist/schemas/2.6.0/bundled/media-buy/sync-creatives-request.json rename to dist/schemas/3.0.0-beta.1/bundled/media-buy/sync-creatives-request.json diff --git a/dist/schemas/2.6.0/bundled/media-buy/sync-creatives-response.json b/dist/schemas/3.0.0-beta.1/bundled/media-buy/sync-creatives-response.json similarity index 100% rename from dist/schemas/2.6.0/bundled/media-buy/sync-creatives-response.json rename to dist/schemas/3.0.0-beta.1/bundled/media-buy/sync-creatives-response.json diff --git a/dist/schemas/2.6.0/bundled/media-buy/update-media-buy-request.json b/dist/schemas/3.0.0-beta.1/bundled/media-buy/update-media-buy-request.json similarity index 100% rename from dist/schemas/2.6.0/bundled/media-buy/update-media-buy-request.json rename to dist/schemas/3.0.0-beta.1/bundled/media-buy/update-media-buy-request.json diff --git a/dist/schemas/2.6.0/bundled/media-buy/update-media-buy-response.json b/dist/schemas/3.0.0-beta.1/bundled/media-buy/update-media-buy-response.json similarity index 100% rename from dist/schemas/2.6.0/bundled/media-buy/update-media-buy-response.json rename to dist/schemas/3.0.0-beta.1/bundled/media-buy/update-media-buy-response.json diff --git a/dist/schemas/2.6.0/bundled/signals/activate-signal-request.json b/dist/schemas/3.0.0-beta.1/bundled/signals/activate-signal-request.json similarity index 100% rename from dist/schemas/2.6.0/bundled/signals/activate-signal-request.json rename to dist/schemas/3.0.0-beta.1/bundled/signals/activate-signal-request.json diff --git a/dist/schemas/2.6.0/bundled/signals/activate-signal-response.json b/dist/schemas/3.0.0-beta.1/bundled/signals/activate-signal-response.json similarity index 100% rename from dist/schemas/2.6.0/bundled/signals/activate-signal-response.json rename to dist/schemas/3.0.0-beta.1/bundled/signals/activate-signal-response.json diff --git a/dist/schemas/2.6.0/bundled/signals/get-signals-request.json b/dist/schemas/3.0.0-beta.1/bundled/signals/get-signals-request.json similarity index 100% rename from dist/schemas/2.6.0/bundled/signals/get-signals-request.json rename to dist/schemas/3.0.0-beta.1/bundled/signals/get-signals-request.json diff --git a/dist/schemas/2.6.0/bundled/signals/get-signals-response.json b/dist/schemas/3.0.0-beta.1/bundled/signals/get-signals-response.json similarity index 100% rename from dist/schemas/2.6.0/bundled/signals/get-signals-response.json rename to dist/schemas/3.0.0-beta.1/bundled/signals/get-signals-response.json diff --git a/dist/schemas/2.6.0/core/activation-key.json b/dist/schemas/3.0.0-beta.1/core/activation-key.json similarity index 100% rename from dist/schemas/2.6.0/core/activation-key.json rename to dist/schemas/3.0.0-beta.1/core/activation-key.json diff --git a/dist/schemas/2.6.0/core/assets/audio-asset.json b/dist/schemas/3.0.0-beta.1/core/assets/audio-asset.json similarity index 100% rename from dist/schemas/2.6.0/core/assets/audio-asset.json rename to dist/schemas/3.0.0-beta.1/core/assets/audio-asset.json diff --git a/dist/schemas/2.6.0/core/assets/css-asset.json b/dist/schemas/3.0.0-beta.1/core/assets/css-asset.json similarity index 100% rename from dist/schemas/2.6.0/core/assets/css-asset.json rename to dist/schemas/3.0.0-beta.1/core/assets/css-asset.json diff --git a/dist/schemas/2.6.0/core/assets/daast-asset.json b/dist/schemas/3.0.0-beta.1/core/assets/daast-asset.json similarity index 100% rename from dist/schemas/2.6.0/core/assets/daast-asset.json rename to dist/schemas/3.0.0-beta.1/core/assets/daast-asset.json diff --git a/dist/schemas/2.6.0/core/assets/html-asset.json b/dist/schemas/3.0.0-beta.1/core/assets/html-asset.json similarity index 100% rename from dist/schemas/2.6.0/core/assets/html-asset.json rename to dist/schemas/3.0.0-beta.1/core/assets/html-asset.json diff --git a/dist/schemas/2.6.0/core/assets/image-asset.json b/dist/schemas/3.0.0-beta.1/core/assets/image-asset.json similarity index 100% rename from dist/schemas/2.6.0/core/assets/image-asset.json rename to dist/schemas/3.0.0-beta.1/core/assets/image-asset.json diff --git a/dist/schemas/2.6.0/core/assets/javascript-asset.json b/dist/schemas/3.0.0-beta.1/core/assets/javascript-asset.json similarity index 100% rename from dist/schemas/2.6.0/core/assets/javascript-asset.json rename to dist/schemas/3.0.0-beta.1/core/assets/javascript-asset.json diff --git a/dist/schemas/2.6.0/core/assets/markdown-asset.json b/dist/schemas/3.0.0-beta.1/core/assets/markdown-asset.json similarity index 100% rename from dist/schemas/2.6.0/core/assets/markdown-asset.json rename to dist/schemas/3.0.0-beta.1/core/assets/markdown-asset.json diff --git a/dist/schemas/2.6.0/core/assets/text-asset.json b/dist/schemas/3.0.0-beta.1/core/assets/text-asset.json similarity index 100% rename from dist/schemas/2.6.0/core/assets/text-asset.json rename to dist/schemas/3.0.0-beta.1/core/assets/text-asset.json diff --git a/dist/schemas/2.6.0/core/assets/url-asset.json b/dist/schemas/3.0.0-beta.1/core/assets/url-asset.json similarity index 100% rename from dist/schemas/2.6.0/core/assets/url-asset.json rename to dist/schemas/3.0.0-beta.1/core/assets/url-asset.json diff --git a/dist/schemas/2.6.0/core/assets/vast-asset.json b/dist/schemas/3.0.0-beta.1/core/assets/vast-asset.json similarity index 100% rename from dist/schemas/2.6.0/core/assets/vast-asset.json rename to dist/schemas/3.0.0-beta.1/core/assets/vast-asset.json diff --git a/dist/schemas/2.6.0/core/assets/video-asset.json b/dist/schemas/3.0.0-beta.1/core/assets/video-asset.json similarity index 100% rename from dist/schemas/2.6.0/core/assets/video-asset.json rename to dist/schemas/3.0.0-beta.1/core/assets/video-asset.json diff --git a/dist/schemas/2.6.0/core/assets/webhook-asset.json b/dist/schemas/3.0.0-beta.1/core/assets/webhook-asset.json similarity index 100% rename from dist/schemas/2.6.0/core/assets/webhook-asset.json rename to dist/schemas/3.0.0-beta.1/core/assets/webhook-asset.json diff --git a/dist/schemas/2.6.0/core/async-response-data.json b/dist/schemas/3.0.0-beta.1/core/async-response-data.json similarity index 100% rename from dist/schemas/2.6.0/core/async-response-data.json rename to dist/schemas/3.0.0-beta.1/core/async-response-data.json diff --git a/dist/schemas/2.6.0/core/brand-manifest-ref.json b/dist/schemas/3.0.0-beta.1/core/brand-manifest-ref.json similarity index 100% rename from dist/schemas/2.6.0/core/brand-manifest-ref.json rename to dist/schemas/3.0.0-beta.1/core/brand-manifest-ref.json diff --git a/dist/schemas/2.6.0/core/brand-manifest.json b/dist/schemas/3.0.0-beta.1/core/brand-manifest.json similarity index 100% rename from dist/schemas/2.6.0/core/brand-manifest.json rename to dist/schemas/3.0.0-beta.1/core/brand-manifest.json diff --git a/dist/schemas/2.6.0/core/context.json b/dist/schemas/3.0.0-beta.1/core/context.json similarity index 100% rename from dist/schemas/2.6.0/core/context.json rename to dist/schemas/3.0.0-beta.1/core/context.json diff --git a/dist/schemas/2.6.0/core/creative-asset.json b/dist/schemas/3.0.0-beta.1/core/creative-asset.json similarity index 100% rename from dist/schemas/2.6.0/core/creative-asset.json rename to dist/schemas/3.0.0-beta.1/core/creative-asset.json diff --git a/dist/schemas/2.6.0/core/creative-assignment.json b/dist/schemas/3.0.0-beta.1/core/creative-assignment.json similarity index 100% rename from dist/schemas/2.6.0/core/creative-assignment.json rename to dist/schemas/3.0.0-beta.1/core/creative-assignment.json diff --git a/dist/schemas/2.6.0/core/creative-filters.json b/dist/schemas/3.0.0-beta.1/core/creative-filters.json similarity index 100% rename from dist/schemas/2.6.0/core/creative-filters.json rename to dist/schemas/3.0.0-beta.1/core/creative-filters.json diff --git a/dist/schemas/2.6.0/core/creative-manifest.json b/dist/schemas/3.0.0-beta.1/core/creative-manifest.json similarity index 100% rename from dist/schemas/2.6.0/core/creative-manifest.json rename to dist/schemas/3.0.0-beta.1/core/creative-manifest.json diff --git a/dist/schemas/2.6.0/core/creative-policy.json b/dist/schemas/3.0.0-beta.1/core/creative-policy.json similarity index 100% rename from dist/schemas/2.6.0/core/creative-policy.json rename to dist/schemas/3.0.0-beta.1/core/creative-policy.json diff --git a/dist/schemas/2.6.0/core/delivery-metrics.json b/dist/schemas/3.0.0-beta.1/core/delivery-metrics.json similarity index 100% rename from dist/schemas/2.6.0/core/delivery-metrics.json rename to dist/schemas/3.0.0-beta.1/core/delivery-metrics.json diff --git a/dist/schemas/2.6.0/core/deployment.json b/dist/schemas/3.0.0-beta.1/core/deployment.json similarity index 100% rename from dist/schemas/2.6.0/core/deployment.json rename to dist/schemas/3.0.0-beta.1/core/deployment.json diff --git a/dist/schemas/2.6.0/core/destination.json b/dist/schemas/3.0.0-beta.1/core/destination.json similarity index 100% rename from dist/schemas/2.6.0/core/destination.json rename to dist/schemas/3.0.0-beta.1/core/destination.json diff --git a/dist/schemas/2.6.0/core/error.json b/dist/schemas/3.0.0-beta.1/core/error.json similarity index 100% rename from dist/schemas/2.6.0/core/error.json rename to dist/schemas/3.0.0-beta.1/core/error.json diff --git a/dist/schemas/2.6.0/core/ext.json b/dist/schemas/3.0.0-beta.1/core/ext.json similarity index 100% rename from dist/schemas/2.6.0/core/ext.json rename to dist/schemas/3.0.0-beta.1/core/ext.json diff --git a/dist/schemas/2.6.0/core/format-id.json b/dist/schemas/3.0.0-beta.1/core/format-id.json similarity index 100% rename from dist/schemas/2.6.0/core/format-id.json rename to dist/schemas/3.0.0-beta.1/core/format-id.json diff --git a/dist/schemas/2.6.0/core/format.json b/dist/schemas/3.0.0-beta.1/core/format.json similarity index 100% rename from dist/schemas/2.6.0/core/format.json rename to dist/schemas/3.0.0-beta.1/core/format.json diff --git a/dist/schemas/2.6.0/core/frequency-cap.json b/dist/schemas/3.0.0-beta.1/core/frequency-cap.json similarity index 100% rename from dist/schemas/2.6.0/core/frequency-cap.json rename to dist/schemas/3.0.0-beta.1/core/frequency-cap.json diff --git a/dist/schemas/2.6.0/core/identifier.json b/dist/schemas/3.0.0-beta.1/core/identifier.json similarity index 100% rename from dist/schemas/2.6.0/core/identifier.json rename to dist/schemas/3.0.0-beta.1/core/identifier.json diff --git a/dist/schemas/2.6.0/core/mcp-webhook-payload.json b/dist/schemas/3.0.0-beta.1/core/mcp-webhook-payload.json similarity index 100% rename from dist/schemas/2.6.0/core/mcp-webhook-payload.json rename to dist/schemas/3.0.0-beta.1/core/mcp-webhook-payload.json diff --git a/dist/schemas/2.6.0/core/measurement.json b/dist/schemas/3.0.0-beta.1/core/measurement.json similarity index 100% rename from dist/schemas/2.6.0/core/measurement.json rename to dist/schemas/3.0.0-beta.1/core/measurement.json diff --git a/dist/schemas/2.6.0/core/media-buy.json b/dist/schemas/3.0.0-beta.1/core/media-buy.json similarity index 100% rename from dist/schemas/2.6.0/core/media-buy.json rename to dist/schemas/3.0.0-beta.1/core/media-buy.json diff --git a/dist/schemas/2.6.0/core/package.json b/dist/schemas/3.0.0-beta.1/core/package.json similarity index 100% rename from dist/schemas/2.6.0/core/package.json rename to dist/schemas/3.0.0-beta.1/core/package.json diff --git a/dist/schemas/2.6.0/core/performance-feedback.json b/dist/schemas/3.0.0-beta.1/core/performance-feedback.json similarity index 100% rename from dist/schemas/2.6.0/core/performance-feedback.json rename to dist/schemas/3.0.0-beta.1/core/performance-feedback.json diff --git a/dist/schemas/2.6.0/core/placement.json b/dist/schemas/3.0.0-beta.1/core/placement.json similarity index 100% rename from dist/schemas/2.6.0/core/placement.json rename to dist/schemas/3.0.0-beta.1/core/placement.json diff --git a/dist/schemas/2.6.0/core/pricing-option.json b/dist/schemas/3.0.0-beta.1/core/pricing-option.json similarity index 100% rename from dist/schemas/2.6.0/core/pricing-option.json rename to dist/schemas/3.0.0-beta.1/core/pricing-option.json diff --git a/dist/schemas/2.6.0/core/product-filters.json b/dist/schemas/3.0.0-beta.1/core/product-filters.json similarity index 100% rename from dist/schemas/2.6.0/core/product-filters.json rename to dist/schemas/3.0.0-beta.1/core/product-filters.json diff --git a/dist/schemas/2.6.0/core/product.json b/dist/schemas/3.0.0-beta.1/core/product.json similarity index 100% rename from dist/schemas/2.6.0/core/product.json rename to dist/schemas/3.0.0-beta.1/core/product.json diff --git a/dist/schemas/2.6.0/core/promoted-offerings.json b/dist/schemas/3.0.0-beta.1/core/promoted-offerings.json similarity index 100% rename from dist/schemas/2.6.0/core/promoted-offerings.json rename to dist/schemas/3.0.0-beta.1/core/promoted-offerings.json diff --git a/dist/schemas/2.6.0/core/promoted-products.json b/dist/schemas/3.0.0-beta.1/core/promoted-products.json similarity index 100% rename from dist/schemas/2.6.0/core/promoted-products.json rename to dist/schemas/3.0.0-beta.1/core/promoted-products.json diff --git a/dist/schemas/2.6.0/core/property-id.json b/dist/schemas/3.0.0-beta.1/core/property-id.json similarity index 100% rename from dist/schemas/2.6.0/core/property-id.json rename to dist/schemas/3.0.0-beta.1/core/property-id.json diff --git a/dist/schemas/2.6.0/core/property-list-ref.json b/dist/schemas/3.0.0-beta.1/core/property-list-ref.json similarity index 100% rename from dist/schemas/2.6.0/core/property-list-ref.json rename to dist/schemas/3.0.0-beta.1/core/property-list-ref.json diff --git a/dist/schemas/2.6.0/core/property-tag.json b/dist/schemas/3.0.0-beta.1/core/property-tag.json similarity index 100% rename from dist/schemas/2.6.0/core/property-tag.json rename to dist/schemas/3.0.0-beta.1/core/property-tag.json diff --git a/dist/schemas/2.6.0/core/property.json b/dist/schemas/3.0.0-beta.1/core/property.json similarity index 100% rename from dist/schemas/2.6.0/core/property.json rename to dist/schemas/3.0.0-beta.1/core/property.json diff --git a/dist/schemas/2.6.0/core/protocol-envelope.json b/dist/schemas/3.0.0-beta.1/core/protocol-envelope.json similarity index 100% rename from dist/schemas/2.6.0/core/protocol-envelope.json rename to dist/schemas/3.0.0-beta.1/core/protocol-envelope.json diff --git a/dist/schemas/2.6.0/core/publisher-property-selector.json b/dist/schemas/3.0.0-beta.1/core/publisher-property-selector.json similarity index 100% rename from dist/schemas/2.6.0/core/publisher-property-selector.json rename to dist/schemas/3.0.0-beta.1/core/publisher-property-selector.json diff --git a/dist/schemas/2.6.0/core/push-notification-config.json b/dist/schemas/3.0.0-beta.1/core/push-notification-config.json similarity index 100% rename from dist/schemas/2.6.0/core/push-notification-config.json rename to dist/schemas/3.0.0-beta.1/core/push-notification-config.json diff --git a/dist/schemas/2.6.0/core/reporting-capabilities.json b/dist/schemas/3.0.0-beta.1/core/reporting-capabilities.json similarity index 100% rename from dist/schemas/2.6.0/core/reporting-capabilities.json rename to dist/schemas/3.0.0-beta.1/core/reporting-capabilities.json diff --git a/dist/schemas/2.6.0/core/response.json b/dist/schemas/3.0.0-beta.1/core/response.json similarity index 100% rename from dist/schemas/2.6.0/core/response.json rename to dist/schemas/3.0.0-beta.1/core/response.json diff --git a/dist/schemas/2.6.0/core/signal-filters.json b/dist/schemas/3.0.0-beta.1/core/signal-filters.json similarity index 100% rename from dist/schemas/2.6.0/core/signal-filters.json rename to dist/schemas/3.0.0-beta.1/core/signal-filters.json diff --git a/dist/schemas/2.6.0/core/start-timing.json b/dist/schemas/3.0.0-beta.1/core/start-timing.json similarity index 100% rename from dist/schemas/2.6.0/core/start-timing.json rename to dist/schemas/3.0.0-beta.1/core/start-timing.json diff --git a/dist/schemas/2.6.0/core/sub-asset.json b/dist/schemas/3.0.0-beta.1/core/sub-asset.json similarity index 100% rename from dist/schemas/2.6.0/core/sub-asset.json rename to dist/schemas/3.0.0-beta.1/core/sub-asset.json diff --git a/dist/schemas/2.6.0/core/targeting.json b/dist/schemas/3.0.0-beta.1/core/targeting.json similarity index 100% rename from dist/schemas/2.6.0/core/targeting.json rename to dist/schemas/3.0.0-beta.1/core/targeting.json diff --git a/dist/schemas/2.6.0/core/tasks-get-request.json b/dist/schemas/3.0.0-beta.1/core/tasks-get-request.json similarity index 100% rename from dist/schemas/2.6.0/core/tasks-get-request.json rename to dist/schemas/3.0.0-beta.1/core/tasks-get-request.json diff --git a/dist/schemas/2.6.0/core/tasks-get-response.json b/dist/schemas/3.0.0-beta.1/core/tasks-get-response.json similarity index 100% rename from dist/schemas/2.6.0/core/tasks-get-response.json rename to dist/schemas/3.0.0-beta.1/core/tasks-get-response.json diff --git a/dist/schemas/2.6.0/core/tasks-list-request.json b/dist/schemas/3.0.0-beta.1/core/tasks-list-request.json similarity index 100% rename from dist/schemas/2.6.0/core/tasks-list-request.json rename to dist/schemas/3.0.0-beta.1/core/tasks-list-request.json diff --git a/dist/schemas/2.6.0/core/tasks-list-response.json b/dist/schemas/3.0.0-beta.1/core/tasks-list-response.json similarity index 100% rename from dist/schemas/2.6.0/core/tasks-list-response.json rename to dist/schemas/3.0.0-beta.1/core/tasks-list-response.json diff --git a/dist/schemas/2.6.0/creative/asset-types/index.json b/dist/schemas/3.0.0-beta.1/creative/asset-types/index.json similarity index 100% rename from dist/schemas/2.6.0/creative/asset-types/index.json rename to dist/schemas/3.0.0-beta.1/creative/asset-types/index.json diff --git a/dist/schemas/2.6.0/creative/list-creative-formats-request.json b/dist/schemas/3.0.0-beta.1/creative/list-creative-formats-request.json similarity index 100% rename from dist/schemas/2.6.0/creative/list-creative-formats-request.json rename to dist/schemas/3.0.0-beta.1/creative/list-creative-formats-request.json diff --git a/dist/schemas/2.6.0/creative/list-creative-formats-response.json b/dist/schemas/3.0.0-beta.1/creative/list-creative-formats-response.json similarity index 100% rename from dist/schemas/2.6.0/creative/list-creative-formats-response.json rename to dist/schemas/3.0.0-beta.1/creative/list-creative-formats-response.json diff --git a/dist/schemas/2.6.0/creative/preview-creative-request.json b/dist/schemas/3.0.0-beta.1/creative/preview-creative-request.json similarity index 100% rename from dist/schemas/2.6.0/creative/preview-creative-request.json rename to dist/schemas/3.0.0-beta.1/creative/preview-creative-request.json diff --git a/dist/schemas/2.6.0/creative/preview-creative-response.json b/dist/schemas/3.0.0-beta.1/creative/preview-creative-response.json similarity index 100% rename from dist/schemas/2.6.0/creative/preview-creative-response.json rename to dist/schemas/3.0.0-beta.1/creative/preview-creative-response.json diff --git a/dist/schemas/2.6.0/creative/preview-render.json b/dist/schemas/3.0.0-beta.1/creative/preview-render.json similarity index 100% rename from dist/schemas/2.6.0/creative/preview-render.json rename to dist/schemas/3.0.0-beta.1/creative/preview-render.json diff --git a/dist/schemas/2.6.0/enums/adcp-domain.json b/dist/schemas/3.0.0-beta.1/enums/adcp-domain.json similarity index 100% rename from dist/schemas/2.6.0/enums/adcp-domain.json rename to dist/schemas/3.0.0-beta.1/enums/adcp-domain.json diff --git a/dist/schemas/2.6.0/enums/asset-content-type.json b/dist/schemas/3.0.0-beta.1/enums/asset-content-type.json similarity index 100% rename from dist/schemas/2.6.0/enums/asset-content-type.json rename to dist/schemas/3.0.0-beta.1/enums/asset-content-type.json diff --git a/dist/schemas/2.6.0/enums/auth-scheme.json b/dist/schemas/3.0.0-beta.1/enums/auth-scheme.json similarity index 100% rename from dist/schemas/2.6.0/enums/auth-scheme.json rename to dist/schemas/3.0.0-beta.1/enums/auth-scheme.json diff --git a/dist/schemas/2.6.0/enums/available-metric.json b/dist/schemas/3.0.0-beta.1/enums/available-metric.json similarity index 100% rename from dist/schemas/2.6.0/enums/available-metric.json rename to dist/schemas/3.0.0-beta.1/enums/available-metric.json diff --git a/dist/schemas/2.6.0/enums/channels.json b/dist/schemas/3.0.0-beta.1/enums/channels.json similarity index 100% rename from dist/schemas/2.6.0/enums/channels.json rename to dist/schemas/3.0.0-beta.1/enums/channels.json diff --git a/dist/schemas/2.6.0/enums/co-branding-requirement.json b/dist/schemas/3.0.0-beta.1/enums/co-branding-requirement.json similarity index 100% rename from dist/schemas/2.6.0/enums/co-branding-requirement.json rename to dist/schemas/3.0.0-beta.1/enums/co-branding-requirement.json diff --git a/dist/schemas/2.6.0/enums/creative-action.json b/dist/schemas/3.0.0-beta.1/enums/creative-action.json similarity index 100% rename from dist/schemas/2.6.0/enums/creative-action.json rename to dist/schemas/3.0.0-beta.1/enums/creative-action.json diff --git a/dist/schemas/2.6.0/enums/creative-agent-capability.json b/dist/schemas/3.0.0-beta.1/enums/creative-agent-capability.json similarity index 100% rename from dist/schemas/2.6.0/enums/creative-agent-capability.json rename to dist/schemas/3.0.0-beta.1/enums/creative-agent-capability.json diff --git a/dist/schemas/2.6.0/enums/creative-sort-field.json b/dist/schemas/3.0.0-beta.1/enums/creative-sort-field.json similarity index 100% rename from dist/schemas/2.6.0/enums/creative-sort-field.json rename to dist/schemas/3.0.0-beta.1/enums/creative-sort-field.json diff --git a/dist/schemas/2.6.0/enums/creative-status.json b/dist/schemas/3.0.0-beta.1/enums/creative-status.json similarity index 100% rename from dist/schemas/2.6.0/enums/creative-status.json rename to dist/schemas/3.0.0-beta.1/enums/creative-status.json diff --git a/dist/schemas/2.6.0/enums/daast-tracking-event.json b/dist/schemas/3.0.0-beta.1/enums/daast-tracking-event.json similarity index 100% rename from dist/schemas/2.6.0/enums/daast-tracking-event.json rename to dist/schemas/3.0.0-beta.1/enums/daast-tracking-event.json diff --git a/dist/schemas/2.6.0/enums/daast-version.json b/dist/schemas/3.0.0-beta.1/enums/daast-version.json similarity index 100% rename from dist/schemas/2.6.0/enums/daast-version.json rename to dist/schemas/3.0.0-beta.1/enums/daast-version.json diff --git a/dist/schemas/2.6.0/enums/delivery-type.json b/dist/schemas/3.0.0-beta.1/enums/delivery-type.json similarity index 100% rename from dist/schemas/2.6.0/enums/delivery-type.json rename to dist/schemas/3.0.0-beta.1/enums/delivery-type.json diff --git a/dist/schemas/2.6.0/enums/dimension-unit.json b/dist/schemas/3.0.0-beta.1/enums/dimension-unit.json similarity index 100% rename from dist/schemas/2.6.0/enums/dimension-unit.json rename to dist/schemas/3.0.0-beta.1/enums/dimension-unit.json diff --git a/dist/schemas/2.6.0/enums/feed-format.json b/dist/schemas/3.0.0-beta.1/enums/feed-format.json similarity index 100% rename from dist/schemas/2.6.0/enums/feed-format.json rename to dist/schemas/3.0.0-beta.1/enums/feed-format.json diff --git a/dist/schemas/2.6.0/enums/feedback-source.json b/dist/schemas/3.0.0-beta.1/enums/feedback-source.json similarity index 100% rename from dist/schemas/2.6.0/enums/feedback-source.json rename to dist/schemas/3.0.0-beta.1/enums/feedback-source.json diff --git a/dist/schemas/2.6.0/enums/format-category.json b/dist/schemas/3.0.0-beta.1/enums/format-category.json similarity index 100% rename from dist/schemas/2.6.0/enums/format-category.json rename to dist/schemas/3.0.0-beta.1/enums/format-category.json diff --git a/dist/schemas/2.6.0/enums/format-id-parameter.json b/dist/schemas/3.0.0-beta.1/enums/format-id-parameter.json similarity index 100% rename from dist/schemas/2.6.0/enums/format-id-parameter.json rename to dist/schemas/3.0.0-beta.1/enums/format-id-parameter.json diff --git a/dist/schemas/2.6.0/enums/frequency-cap-scope.json b/dist/schemas/3.0.0-beta.1/enums/frequency-cap-scope.json similarity index 100% rename from dist/schemas/2.6.0/enums/frequency-cap-scope.json rename to dist/schemas/3.0.0-beta.1/enums/frequency-cap-scope.json diff --git a/dist/schemas/2.6.0/enums/history-entry-type.json b/dist/schemas/3.0.0-beta.1/enums/history-entry-type.json similarity index 100% rename from dist/schemas/2.6.0/enums/history-entry-type.json rename to dist/schemas/3.0.0-beta.1/enums/history-entry-type.json diff --git a/dist/schemas/2.6.0/enums/http-method.json b/dist/schemas/3.0.0-beta.1/enums/http-method.json similarity index 100% rename from dist/schemas/2.6.0/enums/http-method.json rename to dist/schemas/3.0.0-beta.1/enums/http-method.json diff --git a/dist/schemas/2.6.0/enums/identifier-types.json b/dist/schemas/3.0.0-beta.1/enums/identifier-types.json similarity index 100% rename from dist/schemas/2.6.0/enums/identifier-types.json rename to dist/schemas/3.0.0-beta.1/enums/identifier-types.json diff --git a/dist/schemas/2.6.0/enums/javascript-module-type.json b/dist/schemas/3.0.0-beta.1/enums/javascript-module-type.json similarity index 100% rename from dist/schemas/2.6.0/enums/javascript-module-type.json rename to dist/schemas/3.0.0-beta.1/enums/javascript-module-type.json diff --git a/dist/schemas/2.6.0/enums/landing-page-requirement.json b/dist/schemas/3.0.0-beta.1/enums/landing-page-requirement.json similarity index 100% rename from dist/schemas/2.6.0/enums/landing-page-requirement.json rename to dist/schemas/3.0.0-beta.1/enums/landing-page-requirement.json diff --git a/dist/schemas/2.6.0/enums/markdown-flavor.json b/dist/schemas/3.0.0-beta.1/enums/markdown-flavor.json similarity index 100% rename from dist/schemas/2.6.0/enums/markdown-flavor.json rename to dist/schemas/3.0.0-beta.1/enums/markdown-flavor.json diff --git a/dist/schemas/2.6.0/enums/media-buy-status.json b/dist/schemas/3.0.0-beta.1/enums/media-buy-status.json similarity index 100% rename from dist/schemas/2.6.0/enums/media-buy-status.json rename to dist/schemas/3.0.0-beta.1/enums/media-buy-status.json diff --git a/dist/schemas/2.6.0/enums/metric-type.json b/dist/schemas/3.0.0-beta.1/enums/metric-type.json similarity index 100% rename from dist/schemas/2.6.0/enums/metric-type.json rename to dist/schemas/3.0.0-beta.1/enums/metric-type.json diff --git a/dist/schemas/2.6.0/enums/notification-type.json b/dist/schemas/3.0.0-beta.1/enums/notification-type.json similarity index 100% rename from dist/schemas/2.6.0/enums/notification-type.json rename to dist/schemas/3.0.0-beta.1/enums/notification-type.json diff --git a/dist/schemas/2.6.0/enums/pacing.json b/dist/schemas/3.0.0-beta.1/enums/pacing.json similarity index 100% rename from dist/schemas/2.6.0/enums/pacing.json rename to dist/schemas/3.0.0-beta.1/enums/pacing.json diff --git a/dist/schemas/2.6.0/enums/preview-output-format.json b/dist/schemas/3.0.0-beta.1/enums/preview-output-format.json similarity index 100% rename from dist/schemas/2.6.0/enums/preview-output-format.json rename to dist/schemas/3.0.0-beta.1/enums/preview-output-format.json diff --git a/dist/schemas/2.6.0/enums/pricing-model.json b/dist/schemas/3.0.0-beta.1/enums/pricing-model.json similarity index 100% rename from dist/schemas/2.6.0/enums/pricing-model.json rename to dist/schemas/3.0.0-beta.1/enums/pricing-model.json diff --git a/dist/schemas/2.6.0/enums/property-type.json b/dist/schemas/3.0.0-beta.1/enums/property-type.json similarity index 100% rename from dist/schemas/2.6.0/enums/property-type.json rename to dist/schemas/3.0.0-beta.1/enums/property-type.json diff --git a/dist/schemas/2.6.0/enums/publisher-identifier-types.json b/dist/schemas/3.0.0-beta.1/enums/publisher-identifier-types.json similarity index 100% rename from dist/schemas/2.6.0/enums/publisher-identifier-types.json rename to dist/schemas/3.0.0-beta.1/enums/publisher-identifier-types.json diff --git a/dist/schemas/2.6.0/enums/reporting-frequency.json b/dist/schemas/3.0.0-beta.1/enums/reporting-frequency.json similarity index 100% rename from dist/schemas/2.6.0/enums/reporting-frequency.json rename to dist/schemas/3.0.0-beta.1/enums/reporting-frequency.json diff --git a/dist/schemas/2.6.0/enums/signal-catalog-type.json b/dist/schemas/3.0.0-beta.1/enums/signal-catalog-type.json similarity index 100% rename from dist/schemas/2.6.0/enums/signal-catalog-type.json rename to dist/schemas/3.0.0-beta.1/enums/signal-catalog-type.json diff --git a/dist/schemas/2.6.0/enums/sort-direction.json b/dist/schemas/3.0.0-beta.1/enums/sort-direction.json similarity index 100% rename from dist/schemas/2.6.0/enums/sort-direction.json rename to dist/schemas/3.0.0-beta.1/enums/sort-direction.json diff --git a/dist/schemas/2.6.0/enums/standard-format-ids.json b/dist/schemas/3.0.0-beta.1/enums/standard-format-ids.json similarity index 100% rename from dist/schemas/2.6.0/enums/standard-format-ids.json rename to dist/schemas/3.0.0-beta.1/enums/standard-format-ids.json diff --git a/dist/schemas/2.6.0/enums/task-status.json b/dist/schemas/3.0.0-beta.1/enums/task-status.json similarity index 100% rename from dist/schemas/2.6.0/enums/task-status.json rename to dist/schemas/3.0.0-beta.1/enums/task-status.json diff --git a/dist/schemas/2.6.0/enums/task-type.json b/dist/schemas/3.0.0-beta.1/enums/task-type.json similarity index 100% rename from dist/schemas/2.6.0/enums/task-type.json rename to dist/schemas/3.0.0-beta.1/enums/task-type.json diff --git a/dist/schemas/2.6.0/enums/update-frequency.json b/dist/schemas/3.0.0-beta.1/enums/update-frequency.json similarity index 100% rename from dist/schemas/2.6.0/enums/update-frequency.json rename to dist/schemas/3.0.0-beta.1/enums/update-frequency.json diff --git a/dist/schemas/2.6.0/enums/url-asset-type.json b/dist/schemas/3.0.0-beta.1/enums/url-asset-type.json similarity index 100% rename from dist/schemas/2.6.0/enums/url-asset-type.json rename to dist/schemas/3.0.0-beta.1/enums/url-asset-type.json diff --git a/dist/schemas/2.6.0/enums/validation-mode.json b/dist/schemas/3.0.0-beta.1/enums/validation-mode.json similarity index 100% rename from dist/schemas/2.6.0/enums/validation-mode.json rename to dist/schemas/3.0.0-beta.1/enums/validation-mode.json diff --git a/dist/schemas/2.6.0/enums/vast-tracking-event.json b/dist/schemas/3.0.0-beta.1/enums/vast-tracking-event.json similarity index 100% rename from dist/schemas/2.6.0/enums/vast-tracking-event.json rename to dist/schemas/3.0.0-beta.1/enums/vast-tracking-event.json diff --git a/dist/schemas/2.6.0/enums/vast-version.json b/dist/schemas/3.0.0-beta.1/enums/vast-version.json similarity index 100% rename from dist/schemas/2.6.0/enums/vast-version.json rename to dist/schemas/3.0.0-beta.1/enums/vast-version.json diff --git a/dist/schemas/2.6.0/enums/webhook-response-type.json b/dist/schemas/3.0.0-beta.1/enums/webhook-response-type.json similarity index 100% rename from dist/schemas/2.6.0/enums/webhook-response-type.json rename to dist/schemas/3.0.0-beta.1/enums/webhook-response-type.json diff --git a/dist/schemas/2.6.0/enums/webhook-security-method.json b/dist/schemas/3.0.0-beta.1/enums/webhook-security-method.json similarity index 100% rename from dist/schemas/2.6.0/enums/webhook-security-method.json rename to dist/schemas/3.0.0-beta.1/enums/webhook-security-method.json diff --git a/dist/schemas/2.6.0/extensions/extension-meta.json b/dist/schemas/3.0.0-beta.1/extensions/extension-meta.json similarity index 100% rename from dist/schemas/2.6.0/extensions/extension-meta.json rename to dist/schemas/3.0.0-beta.1/extensions/extension-meta.json diff --git a/dist/schemas/2.6.0/extensions/index.json b/dist/schemas/3.0.0-beta.1/extensions/index.json similarity index 100% rename from dist/schemas/2.6.0/extensions/index.json rename to dist/schemas/3.0.0-beta.1/extensions/index.json diff --git a/dist/schemas/2.6.0/index.json b/dist/schemas/3.0.0-beta.1/index.json similarity index 100% rename from dist/schemas/2.6.0/index.json rename to dist/schemas/3.0.0-beta.1/index.json diff --git a/dist/schemas/2.6.0/media-buy/build-creative-request.json b/dist/schemas/3.0.0-beta.1/media-buy/build-creative-request.json similarity index 100% rename from dist/schemas/2.6.0/media-buy/build-creative-request.json rename to dist/schemas/3.0.0-beta.1/media-buy/build-creative-request.json diff --git a/dist/schemas/2.6.0/media-buy/build-creative-response.json b/dist/schemas/3.0.0-beta.1/media-buy/build-creative-response.json similarity index 100% rename from dist/schemas/2.6.0/media-buy/build-creative-response.json rename to dist/schemas/3.0.0-beta.1/media-buy/build-creative-response.json diff --git a/dist/schemas/2.6.0/media-buy/create-media-buy-async-response-input-required.json b/dist/schemas/3.0.0-beta.1/media-buy/create-media-buy-async-response-input-required.json similarity index 100% rename from dist/schemas/2.6.0/media-buy/create-media-buy-async-response-input-required.json rename to dist/schemas/3.0.0-beta.1/media-buy/create-media-buy-async-response-input-required.json diff --git a/dist/schemas/2.6.0/media-buy/create-media-buy-async-response-submitted.json b/dist/schemas/3.0.0-beta.1/media-buy/create-media-buy-async-response-submitted.json similarity index 100% rename from dist/schemas/2.6.0/media-buy/create-media-buy-async-response-submitted.json rename to dist/schemas/3.0.0-beta.1/media-buy/create-media-buy-async-response-submitted.json diff --git a/dist/schemas/2.6.0/media-buy/create-media-buy-async-response-working.json b/dist/schemas/3.0.0-beta.1/media-buy/create-media-buy-async-response-working.json similarity index 100% rename from dist/schemas/2.6.0/media-buy/create-media-buy-async-response-working.json rename to dist/schemas/3.0.0-beta.1/media-buy/create-media-buy-async-response-working.json diff --git a/dist/schemas/2.6.0/media-buy/create-media-buy-request.json b/dist/schemas/3.0.0-beta.1/media-buy/create-media-buy-request.json similarity index 100% rename from dist/schemas/2.6.0/media-buy/create-media-buy-request.json rename to dist/schemas/3.0.0-beta.1/media-buy/create-media-buy-request.json diff --git a/dist/schemas/2.6.0/media-buy/create-media-buy-response.json b/dist/schemas/3.0.0-beta.1/media-buy/create-media-buy-response.json similarity index 100% rename from dist/schemas/2.6.0/media-buy/create-media-buy-response.json rename to dist/schemas/3.0.0-beta.1/media-buy/create-media-buy-response.json diff --git a/dist/schemas/2.6.0/media-buy/get-media-buy-delivery-request.json b/dist/schemas/3.0.0-beta.1/media-buy/get-media-buy-delivery-request.json similarity index 100% rename from dist/schemas/2.6.0/media-buy/get-media-buy-delivery-request.json rename to dist/schemas/3.0.0-beta.1/media-buy/get-media-buy-delivery-request.json diff --git a/dist/schemas/2.6.0/media-buy/get-media-buy-delivery-response.json b/dist/schemas/3.0.0-beta.1/media-buy/get-media-buy-delivery-response.json similarity index 100% rename from dist/schemas/2.6.0/media-buy/get-media-buy-delivery-response.json rename to dist/schemas/3.0.0-beta.1/media-buy/get-media-buy-delivery-response.json diff --git a/dist/schemas/2.6.0/media-buy/get-products-async-response-input-required.json b/dist/schemas/3.0.0-beta.1/media-buy/get-products-async-response-input-required.json similarity index 100% rename from dist/schemas/2.6.0/media-buy/get-products-async-response-input-required.json rename to dist/schemas/3.0.0-beta.1/media-buy/get-products-async-response-input-required.json diff --git a/dist/schemas/2.6.0/media-buy/get-products-async-response-submitted.json b/dist/schemas/3.0.0-beta.1/media-buy/get-products-async-response-submitted.json similarity index 100% rename from dist/schemas/2.6.0/media-buy/get-products-async-response-submitted.json rename to dist/schemas/3.0.0-beta.1/media-buy/get-products-async-response-submitted.json diff --git a/dist/schemas/2.6.0/media-buy/get-products-async-response-working.json b/dist/schemas/3.0.0-beta.1/media-buy/get-products-async-response-working.json similarity index 100% rename from dist/schemas/2.6.0/media-buy/get-products-async-response-working.json rename to dist/schemas/3.0.0-beta.1/media-buy/get-products-async-response-working.json diff --git a/dist/schemas/2.6.0/media-buy/get-products-request.json b/dist/schemas/3.0.0-beta.1/media-buy/get-products-request.json similarity index 100% rename from dist/schemas/2.6.0/media-buy/get-products-request.json rename to dist/schemas/3.0.0-beta.1/media-buy/get-products-request.json diff --git a/dist/schemas/2.6.0/media-buy/get-products-response.json b/dist/schemas/3.0.0-beta.1/media-buy/get-products-response.json similarity index 100% rename from dist/schemas/2.6.0/media-buy/get-products-response.json rename to dist/schemas/3.0.0-beta.1/media-buy/get-products-response.json diff --git a/dist/schemas/2.6.0/media-buy/list-authorized-properties-request.json b/dist/schemas/3.0.0-beta.1/media-buy/list-authorized-properties-request.json similarity index 100% rename from dist/schemas/2.6.0/media-buy/list-authorized-properties-request.json rename to dist/schemas/3.0.0-beta.1/media-buy/list-authorized-properties-request.json diff --git a/dist/schemas/2.6.0/media-buy/list-authorized-properties-response.json b/dist/schemas/3.0.0-beta.1/media-buy/list-authorized-properties-response.json similarity index 100% rename from dist/schemas/2.6.0/media-buy/list-authorized-properties-response.json rename to dist/schemas/3.0.0-beta.1/media-buy/list-authorized-properties-response.json diff --git a/dist/schemas/2.6.0/media-buy/list-creative-formats-request.json b/dist/schemas/3.0.0-beta.1/media-buy/list-creative-formats-request.json similarity index 100% rename from dist/schemas/2.6.0/media-buy/list-creative-formats-request.json rename to dist/schemas/3.0.0-beta.1/media-buy/list-creative-formats-request.json diff --git a/dist/schemas/2.6.0/media-buy/list-creative-formats-response.json b/dist/schemas/3.0.0-beta.1/media-buy/list-creative-formats-response.json similarity index 100% rename from dist/schemas/2.6.0/media-buy/list-creative-formats-response.json rename to dist/schemas/3.0.0-beta.1/media-buy/list-creative-formats-response.json diff --git a/dist/schemas/2.6.0/media-buy/list-creatives-request.json b/dist/schemas/3.0.0-beta.1/media-buy/list-creatives-request.json similarity index 100% rename from dist/schemas/2.6.0/media-buy/list-creatives-request.json rename to dist/schemas/3.0.0-beta.1/media-buy/list-creatives-request.json diff --git a/dist/schemas/2.6.0/media-buy/list-creatives-response.json b/dist/schemas/3.0.0-beta.1/media-buy/list-creatives-response.json similarity index 100% rename from dist/schemas/2.6.0/media-buy/list-creatives-response.json rename to dist/schemas/3.0.0-beta.1/media-buy/list-creatives-response.json diff --git a/dist/schemas/2.6.0/media-buy/package-request.json b/dist/schemas/3.0.0-beta.1/media-buy/package-request.json similarity index 100% rename from dist/schemas/2.6.0/media-buy/package-request.json rename to dist/schemas/3.0.0-beta.1/media-buy/package-request.json diff --git a/dist/schemas/2.6.0/media-buy/provide-performance-feedback-request.json b/dist/schemas/3.0.0-beta.1/media-buy/provide-performance-feedback-request.json similarity index 100% rename from dist/schemas/2.6.0/media-buy/provide-performance-feedback-request.json rename to dist/schemas/3.0.0-beta.1/media-buy/provide-performance-feedback-request.json diff --git a/dist/schemas/2.6.0/media-buy/provide-performance-feedback-response.json b/dist/schemas/3.0.0-beta.1/media-buy/provide-performance-feedback-response.json similarity index 100% rename from dist/schemas/2.6.0/media-buy/provide-performance-feedback-response.json rename to dist/schemas/3.0.0-beta.1/media-buy/provide-performance-feedback-response.json diff --git a/dist/schemas/2.6.0/media-buy/sync-creatives-async-response-input-required.json b/dist/schemas/3.0.0-beta.1/media-buy/sync-creatives-async-response-input-required.json similarity index 100% rename from dist/schemas/2.6.0/media-buy/sync-creatives-async-response-input-required.json rename to dist/schemas/3.0.0-beta.1/media-buy/sync-creatives-async-response-input-required.json diff --git a/dist/schemas/2.6.0/media-buy/sync-creatives-async-response-submitted.json b/dist/schemas/3.0.0-beta.1/media-buy/sync-creatives-async-response-submitted.json similarity index 100% rename from dist/schemas/2.6.0/media-buy/sync-creatives-async-response-submitted.json rename to dist/schemas/3.0.0-beta.1/media-buy/sync-creatives-async-response-submitted.json diff --git a/dist/schemas/2.6.0/media-buy/sync-creatives-async-response-working.json b/dist/schemas/3.0.0-beta.1/media-buy/sync-creatives-async-response-working.json similarity index 100% rename from dist/schemas/2.6.0/media-buy/sync-creatives-async-response-working.json rename to dist/schemas/3.0.0-beta.1/media-buy/sync-creatives-async-response-working.json diff --git a/dist/schemas/2.6.0/media-buy/sync-creatives-request.json b/dist/schemas/3.0.0-beta.1/media-buy/sync-creatives-request.json similarity index 100% rename from dist/schemas/2.6.0/media-buy/sync-creatives-request.json rename to dist/schemas/3.0.0-beta.1/media-buy/sync-creatives-request.json diff --git a/dist/schemas/2.6.0/media-buy/sync-creatives-response.json b/dist/schemas/3.0.0-beta.1/media-buy/sync-creatives-response.json similarity index 100% rename from dist/schemas/2.6.0/media-buy/sync-creatives-response.json rename to dist/schemas/3.0.0-beta.1/media-buy/sync-creatives-response.json diff --git a/dist/schemas/2.6.0/media-buy/update-media-buy-async-response-input-required.json b/dist/schemas/3.0.0-beta.1/media-buy/update-media-buy-async-response-input-required.json similarity index 100% rename from dist/schemas/2.6.0/media-buy/update-media-buy-async-response-input-required.json rename to dist/schemas/3.0.0-beta.1/media-buy/update-media-buy-async-response-input-required.json diff --git a/dist/schemas/2.6.0/media-buy/update-media-buy-async-response-submitted.json b/dist/schemas/3.0.0-beta.1/media-buy/update-media-buy-async-response-submitted.json similarity index 100% rename from dist/schemas/2.6.0/media-buy/update-media-buy-async-response-submitted.json rename to dist/schemas/3.0.0-beta.1/media-buy/update-media-buy-async-response-submitted.json diff --git a/dist/schemas/2.6.0/media-buy/update-media-buy-async-response-working.json b/dist/schemas/3.0.0-beta.1/media-buy/update-media-buy-async-response-working.json similarity index 100% rename from dist/schemas/2.6.0/media-buy/update-media-buy-async-response-working.json rename to dist/schemas/3.0.0-beta.1/media-buy/update-media-buy-async-response-working.json diff --git a/dist/schemas/2.6.0/media-buy/update-media-buy-request.json b/dist/schemas/3.0.0-beta.1/media-buy/update-media-buy-request.json similarity index 100% rename from dist/schemas/2.6.0/media-buy/update-media-buy-request.json rename to dist/schemas/3.0.0-beta.1/media-buy/update-media-buy-request.json diff --git a/dist/schemas/2.6.0/media-buy/update-media-buy-response.json b/dist/schemas/3.0.0-beta.1/media-buy/update-media-buy-response.json similarity index 100% rename from dist/schemas/2.6.0/media-buy/update-media-buy-response.json rename to dist/schemas/3.0.0-beta.1/media-buy/update-media-buy-response.json diff --git a/dist/schemas/2.6.0/pricing-options/cpc-option.json b/dist/schemas/3.0.0-beta.1/pricing-options/cpc-option.json similarity index 100% rename from dist/schemas/2.6.0/pricing-options/cpc-option.json rename to dist/schemas/3.0.0-beta.1/pricing-options/cpc-option.json diff --git a/dist/schemas/2.6.0/pricing-options/cpcv-option.json b/dist/schemas/3.0.0-beta.1/pricing-options/cpcv-option.json similarity index 100% rename from dist/schemas/2.6.0/pricing-options/cpcv-option.json rename to dist/schemas/3.0.0-beta.1/pricing-options/cpcv-option.json diff --git a/dist/schemas/2.6.0/pricing-options/cpm-auction-option.json b/dist/schemas/3.0.0-beta.1/pricing-options/cpm-auction-option.json similarity index 100% rename from dist/schemas/2.6.0/pricing-options/cpm-auction-option.json rename to dist/schemas/3.0.0-beta.1/pricing-options/cpm-auction-option.json diff --git a/dist/schemas/2.6.0/pricing-options/cpm-fixed-option.json b/dist/schemas/3.0.0-beta.1/pricing-options/cpm-fixed-option.json similarity index 100% rename from dist/schemas/2.6.0/pricing-options/cpm-fixed-option.json rename to dist/schemas/3.0.0-beta.1/pricing-options/cpm-fixed-option.json diff --git a/dist/schemas/2.6.0/pricing-options/cpp-option.json b/dist/schemas/3.0.0-beta.1/pricing-options/cpp-option.json similarity index 100% rename from dist/schemas/2.6.0/pricing-options/cpp-option.json rename to dist/schemas/3.0.0-beta.1/pricing-options/cpp-option.json diff --git a/dist/schemas/2.6.0/pricing-options/cpv-option.json b/dist/schemas/3.0.0-beta.1/pricing-options/cpv-option.json similarity index 100% rename from dist/schemas/2.6.0/pricing-options/cpv-option.json rename to dist/schemas/3.0.0-beta.1/pricing-options/cpv-option.json diff --git a/dist/schemas/2.6.0/pricing-options/flat-rate-option.json b/dist/schemas/3.0.0-beta.1/pricing-options/flat-rate-option.json similarity index 100% rename from dist/schemas/2.6.0/pricing-options/flat-rate-option.json rename to dist/schemas/3.0.0-beta.1/pricing-options/flat-rate-option.json diff --git a/dist/schemas/2.6.0/pricing-options/vcpm-auction-option.json b/dist/schemas/3.0.0-beta.1/pricing-options/vcpm-auction-option.json similarity index 100% rename from dist/schemas/2.6.0/pricing-options/vcpm-auction-option.json rename to dist/schemas/3.0.0-beta.1/pricing-options/vcpm-auction-option.json diff --git a/dist/schemas/2.6.0/pricing-options/vcpm-fixed-option.json b/dist/schemas/3.0.0-beta.1/pricing-options/vcpm-fixed-option.json similarity index 100% rename from dist/schemas/2.6.0/pricing-options/vcpm-fixed-option.json rename to dist/schemas/3.0.0-beta.1/pricing-options/vcpm-fixed-option.json diff --git a/dist/schemas/2.6.0/property/authorization-result.json b/dist/schemas/3.0.0-beta.1/property/authorization-result.json similarity index 100% rename from dist/schemas/2.6.0/property/authorization-result.json rename to dist/schemas/3.0.0-beta.1/property/authorization-result.json diff --git a/dist/schemas/2.6.0/property/base-property-source.json b/dist/schemas/3.0.0-beta.1/property/base-property-source.json similarity index 100% rename from dist/schemas/2.6.0/property/base-property-source.json rename to dist/schemas/3.0.0-beta.1/property/base-property-source.json diff --git a/dist/schemas/2.6.0/property/create-property-list-request.json b/dist/schemas/3.0.0-beta.1/property/create-property-list-request.json similarity index 100% rename from dist/schemas/2.6.0/property/create-property-list-request.json rename to dist/schemas/3.0.0-beta.1/property/create-property-list-request.json diff --git a/dist/schemas/2.6.0/property/create-property-list-response.json b/dist/schemas/3.0.0-beta.1/property/create-property-list-response.json similarity index 100% rename from dist/schemas/2.6.0/property/create-property-list-response.json rename to dist/schemas/3.0.0-beta.1/property/create-property-list-response.json diff --git a/dist/schemas/2.6.0/property/delete-property-list-request.json b/dist/schemas/3.0.0-beta.1/property/delete-property-list-request.json similarity index 100% rename from dist/schemas/2.6.0/property/delete-property-list-request.json rename to dist/schemas/3.0.0-beta.1/property/delete-property-list-request.json diff --git a/dist/schemas/2.6.0/property/delete-property-list-response.json b/dist/schemas/3.0.0-beta.1/property/delete-property-list-response.json similarity index 100% rename from dist/schemas/2.6.0/property/delete-property-list-response.json rename to dist/schemas/3.0.0-beta.1/property/delete-property-list-response.json diff --git a/dist/schemas/2.6.0/property/delivery-record.json b/dist/schemas/3.0.0-beta.1/property/delivery-record.json similarity index 100% rename from dist/schemas/2.6.0/property/delivery-record.json rename to dist/schemas/3.0.0-beta.1/property/delivery-record.json diff --git a/dist/schemas/2.6.0/property/feature-requirement.json b/dist/schemas/3.0.0-beta.1/property/feature-requirement.json similarity index 100% rename from dist/schemas/2.6.0/property/feature-requirement.json rename to dist/schemas/3.0.0-beta.1/property/feature-requirement.json diff --git a/dist/schemas/2.6.0/property/get-property-features-request.json b/dist/schemas/3.0.0-beta.1/property/get-property-features-request.json similarity index 100% rename from dist/schemas/2.6.0/property/get-property-features-request.json rename to dist/schemas/3.0.0-beta.1/property/get-property-features-request.json diff --git a/dist/schemas/2.6.0/property/get-property-features-response.json b/dist/schemas/3.0.0-beta.1/property/get-property-features-response.json similarity index 100% rename from dist/schemas/2.6.0/property/get-property-features-response.json rename to dist/schemas/3.0.0-beta.1/property/get-property-features-response.json diff --git a/dist/schemas/2.6.0/property/get-property-list-request.json b/dist/schemas/3.0.0-beta.1/property/get-property-list-request.json similarity index 100% rename from dist/schemas/2.6.0/property/get-property-list-request.json rename to dist/schemas/3.0.0-beta.1/property/get-property-list-request.json diff --git a/dist/schemas/2.6.0/property/get-property-list-response.json b/dist/schemas/3.0.0-beta.1/property/get-property-list-response.json similarity index 100% rename from dist/schemas/2.6.0/property/get-property-list-response.json rename to dist/schemas/3.0.0-beta.1/property/get-property-list-response.json diff --git a/dist/schemas/2.6.0/property/list-property-features-request.json b/dist/schemas/3.0.0-beta.1/property/list-property-features-request.json similarity index 100% rename from dist/schemas/2.6.0/property/list-property-features-request.json rename to dist/schemas/3.0.0-beta.1/property/list-property-features-request.json diff --git a/dist/schemas/2.6.0/property/list-property-features-response.json b/dist/schemas/3.0.0-beta.1/property/list-property-features-response.json similarity index 100% rename from dist/schemas/2.6.0/property/list-property-features-response.json rename to dist/schemas/3.0.0-beta.1/property/list-property-features-response.json diff --git a/dist/schemas/2.6.0/property/list-property-lists-request.json b/dist/schemas/3.0.0-beta.1/property/list-property-lists-request.json similarity index 100% rename from dist/schemas/2.6.0/property/list-property-lists-request.json rename to dist/schemas/3.0.0-beta.1/property/list-property-lists-request.json diff --git a/dist/schemas/2.6.0/property/list-property-lists-response.json b/dist/schemas/3.0.0-beta.1/property/list-property-lists-response.json similarity index 100% rename from dist/schemas/2.6.0/property/list-property-lists-response.json rename to dist/schemas/3.0.0-beta.1/property/list-property-lists-response.json diff --git a/dist/schemas/2.6.0/property/property-error.json b/dist/schemas/3.0.0-beta.1/property/property-error.json similarity index 100% rename from dist/schemas/2.6.0/property/property-error.json rename to dist/schemas/3.0.0-beta.1/property/property-error.json diff --git a/dist/schemas/2.6.0/property/property-feature-definition.json b/dist/schemas/3.0.0-beta.1/property/property-feature-definition.json similarity index 100% rename from dist/schemas/2.6.0/property/property-feature-definition.json rename to dist/schemas/3.0.0-beta.1/property/property-feature-definition.json diff --git a/dist/schemas/2.6.0/property/property-feature-result.json b/dist/schemas/3.0.0-beta.1/property/property-feature-result.json similarity index 100% rename from dist/schemas/2.6.0/property/property-feature-result.json rename to dist/schemas/3.0.0-beta.1/property/property-feature-result.json diff --git a/dist/schemas/2.6.0/property/property-feature-value.json b/dist/schemas/3.0.0-beta.1/property/property-feature-value.json similarity index 100% rename from dist/schemas/2.6.0/property/property-feature-value.json rename to dist/schemas/3.0.0-beta.1/property/property-feature-value.json diff --git a/dist/schemas/2.6.0/property/property-feature.json b/dist/schemas/3.0.0-beta.1/property/property-feature.json similarity index 100% rename from dist/schemas/2.6.0/property/property-feature.json rename to dist/schemas/3.0.0-beta.1/property/property-feature.json diff --git a/dist/schemas/2.6.0/property/property-list-changed-webhook.json b/dist/schemas/3.0.0-beta.1/property/property-list-changed-webhook.json similarity index 100% rename from dist/schemas/2.6.0/property/property-list-changed-webhook.json rename to dist/schemas/3.0.0-beta.1/property/property-list-changed-webhook.json diff --git a/dist/schemas/2.6.0/property/property-list-filters.json b/dist/schemas/3.0.0-beta.1/property/property-list-filters.json similarity index 100% rename from dist/schemas/2.6.0/property/property-list-filters.json rename to dist/schemas/3.0.0-beta.1/property/property-list-filters.json diff --git a/dist/schemas/2.6.0/property/property-list.json b/dist/schemas/3.0.0-beta.1/property/property-list.json similarity index 100% rename from dist/schemas/2.6.0/property/property-list.json rename to dist/schemas/3.0.0-beta.1/property/property-list.json diff --git a/dist/schemas/2.6.0/property/update-property-list-request.json b/dist/schemas/3.0.0-beta.1/property/update-property-list-request.json similarity index 100% rename from dist/schemas/2.6.0/property/update-property-list-request.json rename to dist/schemas/3.0.0-beta.1/property/update-property-list-request.json diff --git a/dist/schemas/2.6.0/property/update-property-list-response.json b/dist/schemas/3.0.0-beta.1/property/update-property-list-response.json similarity index 100% rename from dist/schemas/2.6.0/property/update-property-list-response.json rename to dist/schemas/3.0.0-beta.1/property/update-property-list-response.json diff --git a/dist/schemas/2.6.0/property/validate-property-delivery-request.json b/dist/schemas/3.0.0-beta.1/property/validate-property-delivery-request.json similarity index 100% rename from dist/schemas/2.6.0/property/validate-property-delivery-request.json rename to dist/schemas/3.0.0-beta.1/property/validate-property-delivery-request.json diff --git a/dist/schemas/2.6.0/property/validate-property-delivery-response.json b/dist/schemas/3.0.0-beta.1/property/validate-property-delivery-response.json similarity index 100% rename from dist/schemas/2.6.0/property/validate-property-delivery-response.json rename to dist/schemas/3.0.0-beta.1/property/validate-property-delivery-response.json diff --git a/dist/schemas/2.6.0/property/validation-result.json b/dist/schemas/3.0.0-beta.1/property/validation-result.json similarity index 100% rename from dist/schemas/2.6.0/property/validation-result.json rename to dist/schemas/3.0.0-beta.1/property/validation-result.json diff --git a/dist/schemas/2.6.0/protocols/adcp-extension.json b/dist/schemas/3.0.0-beta.1/protocols/adcp-extension.json similarity index 100% rename from dist/schemas/2.6.0/protocols/adcp-extension.json rename to dist/schemas/3.0.0-beta.1/protocols/adcp-extension.json diff --git a/dist/schemas/2.6.0/signals/activate-signal-request.json b/dist/schemas/3.0.0-beta.1/signals/activate-signal-request.json similarity index 100% rename from dist/schemas/2.6.0/signals/activate-signal-request.json rename to dist/schemas/3.0.0-beta.1/signals/activate-signal-request.json diff --git a/dist/schemas/2.6.0/signals/activate-signal-response.json b/dist/schemas/3.0.0-beta.1/signals/activate-signal-response.json similarity index 100% rename from dist/schemas/2.6.0/signals/activate-signal-response.json rename to dist/schemas/3.0.0-beta.1/signals/activate-signal-response.json diff --git a/dist/schemas/2.6.0/signals/get-signals-request.json b/dist/schemas/3.0.0-beta.1/signals/get-signals-request.json similarity index 100% rename from dist/schemas/2.6.0/signals/get-signals-request.json rename to dist/schemas/3.0.0-beta.1/signals/get-signals-request.json diff --git a/dist/schemas/2.6.0/signals/get-signals-response.json b/dist/schemas/3.0.0-beta.1/signals/get-signals-response.json similarity index 100% rename from dist/schemas/2.6.0/signals/get-signals-response.json rename to dist/schemas/3.0.0-beta.1/signals/get-signals-response.json diff --git a/docs.json b/docs.json index 5c3a77b754..2e1d590e79 100644 --- a/docs.json +++ b/docs.json @@ -52,7 +52,7 @@ "navigation": { "versions": [ { - "version": "2.6", + "version": "3.0-beta", "groups": [ { "group": "Getting Started", diff --git a/package.json b/package.json index 58e4386b8b..ccde0040ea 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "adcontextprotocol", - "version": "2.6.0", + "version": "3.0.0-beta.1", "private": true, "type": "module", "scripts": { diff --git a/static/schemas/source/index.json b/static/schemas/source/index.json index 56c7eb4c41..841f6ec034 100644 --- a/static/schemas/source/index.json +++ b/static/schemas/source/index.json @@ -4,7 +4,7 @@ "title": "AdCP Schema Registry v1", "version": "1.0.0", "description": "Registry of all AdCP JSON schemas for validation and discovery", - "adcp_version": "2.6.0", + "adcp_version": "3.0.0-beta.1", "standard_formats_version": "2.0.0", "versioning": { "note": "AdCP uses path-based versioning. The schema URL path (/schemas/) indicates the version. Individual request/response schemas do NOT include adcp_version fields. Compatibility follows semantic versioning rules." From 3a950321040df5a6d672b480542ab71153ce3a30 Mon Sep 17 00:00:00 2001 From: Brian O'Kelley Date: Sat, 24 Jan 2026 13:18:41 -0500 Subject: [PATCH 33/34] chore: configure changesets for beta releases - Enter changeset pre-release mode with 'beta' tag - Fix release-docs workflow to handle prerelease versions: - Extract "3.0-beta" from "3.0.0-beta.1" for docs.json labels - Update regex to match prerelease paths like dist/docs/3.0.0-beta.1/ Co-Authored-By: Claude Opus 4.5 --- .changeset/pre.json | 8 ++++++++ .github/workflows/release-docs.yml | 23 +++++++++++++++++------ 2 files changed, 25 insertions(+), 6 deletions(-) create mode 100644 .changeset/pre.json diff --git a/.changeset/pre.json b/.changeset/pre.json new file mode 100644 index 0000000000..8efb78af9a --- /dev/null +++ b/.changeset/pre.json @@ -0,0 +1,8 @@ +{ + "mode": "pre", + "tag": "beta", + "initialVersions": { + "adcontextprotocol": "3.0.0-beta.1" + }, + "changesets": [] +} diff --git a/.github/workflows/release-docs.yml b/.github/workflows/release-docs.yml index 010ba9b71d..ee89354329 100644 --- a/.github/workflows/release-docs.yml +++ b/.github/workflows/release-docs.yml @@ -24,13 +24,23 @@ jobs: if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then VERSION="${{ inputs.version }}" else - # Extract version from tag (v2.6.0 -> 2.6.0) + # Extract version from tag (v3.0.0-beta.1 -> 3.0.0-beta.1) VERSION="${GITHUB_REF_NAME#v}" fi echo "version=$VERSION" >> $GITHUB_OUTPUT - # Extract major.minor for docs.json version label (2.6.0 -> 2.6) - MAJOR_MINOR=$(echo "$VERSION" | cut -d. -f1,2) + # Extract major.minor for docs.json version label + # For "3.0.0-beta.1" -> "3.0-beta" + # For "3.0.1" -> "3.0" + if [[ "$VERSION" == *"-"* ]]; then + # Has prerelease suffix (e.g., 3.0.0-beta.1 -> 3.0-beta) + BASE_VERSION=$(echo "$VERSION" | cut -d- -f1) + PRERELEASE_TAG=$(echo "$VERSION" | cut -d- -f2 | cut -d. -f1) + MAJOR_MINOR="$(echo "$BASE_VERSION" | cut -d. -f1,2)-$PRERELEASE_TAG" + else + # Standard version (e.g., 3.0.1 -> 3.0) + MAJOR_MINOR=$(echo "$VERSION" | cut -d. -f1,2) + fi echo "major_minor=$MAJOR_MINOR" >> $GITHUB_OUTPUT - name: Checkout main branch @@ -83,7 +93,8 @@ jobs: if [ -n "$EXISTING" ]; then echo "Version $MAJOR_MINOR already exists in docs.json, updating paths to $VERSION" # Update existing version's paths to point to the new patch version - jq --arg old_pattern "dist/docs/[0-9]+\\.[0-9]+\\.[0-9]+/" \ + # Regex matches both standard (3.0.1) and prerelease (3.0.0-beta.1) versions + jq --arg old_pattern "dist/docs/[0-9]+\\.[0-9]+\\.[0-9]+(-[a-zA-Z]+\\.[0-9]+)?/" \ --arg new_path "dist/docs/$VERSION/" \ --arg major_minor "$MAJOR_MINOR" \ ' @@ -97,8 +108,8 @@ jobs: . end elif type == "string" then - if test("^dist/docs/[0-9]+\\.[0-9]+\\.[0-9]+/") then - sub("^dist/docs/[0-9]+\\.[0-9]+\\.[0-9]+/"; $new_path) + if test("^dist/docs/[0-9]+\\.[0-9]+\\.[0-9]+(-[a-zA-Z]+\\.[0-9]+)?/") then + sub("^dist/docs/[0-9]+\\.[0-9]+\\.[0-9]+(-[a-zA-Z]+\\.[0-9]+)?/"; $new_path) else . end From 61d45ffc7d0a88b45d505df9edcc7aee1609413f Mon Sep 17 00:00:00 2001 From: Brian O'Kelley Date: Sat, 24 Jan 2026 13:26:53 -0500 Subject: [PATCH 34/34] docs: add 3.0.0-beta.1 release documentation - Update intro.mdx banner for v3.0.0-beta.1 - Add comprehensive release notes section covering: - Media Channel Taxonomy breaking changes (19 new channels) - Creative assignments with weighting - Geo targeting with named systems - get_adcp_capabilities task - Governance Protocol (property lists, content standards) - Unified asset discovery - Deprecation notices and migration checklist Co-Authored-By: Claude Opus 4.5 --- docs/intro.mdx | 4 +- docs/reference/release-notes.mdx | 209 +++++++++++++++++++++++++++++++ 2 files changed, 211 insertions(+), 2 deletions(-) diff --git a/docs/intro.mdx b/docs/intro.mdx index 2d095a18ba..91db625347 100644 --- a/docs/intro.mdx +++ b/docs/intro.mdx @@ -7,9 +7,9 @@ keywords: [advertising automation protocol, programmatic advertising API, MCP ad -**🎉 AdCP v2.6.0 Released** +**🚀 AdCP v3.0.0-beta.1 Available** -Asset discovery release featuring unified `assets` field in format schema for discovering both required and optional assets. Buyers and AI agents can now see ALL assets a format supports. [See what's new →](/docs/reference/release-notes) +Major release with breaking changes: new Media Channel Taxonomy (19 planning-oriented channels), creative assignments with weighting, and `get_adcp_capabilities` for protocol-level discovery. Plus new Governance Protocol for property lists and content standards. [See what's new →](/docs/reference/release-notes) Welcome to the Ad Context Protocol (AdCP) documentation—the open standard for agentic advertising. diff --git a/docs/reference/release-notes.mdx b/docs/reference/release-notes.mdx index e9e965e492..2c9f258e3b 100644 --- a/docs/reference/release-notes.mdx +++ b/docs/reference/release-notes.mdx @@ -10,6 +10,215 @@ High-level summaries of major AdCP releases with migration guidance. For detaile --- +## Version 3.0.0-beta.1 + +**Status:** Beta | [Full Changelog](https://github.com/adcontextprotocol/adcp/blob/main/CHANGELOG.md#300-beta1) + + +**This is a beta release.** While the API is stable for testing, breaking changes may occur before the final 3.0.0 release. We encourage early adopters to test and provide feedback. + + +### What's New + +Version 3.0.0 is a **major release** introducing the Governance Protocol for brand safety and inventory curation, a complete overhaul of media channel definitions, and protocol-level capability discovery. This release establishes the foundation for enterprise-scale brand safety workflows. + +**🎯 Key Themes:** + +1. **Media Channel Taxonomy** - Complete overhaul of channel enum values to align with how buyers actually plan and allocate budgets across 19 planning-oriented media channels. + +2. **Governance Protocol** - New protocol domain for property lists, content standards, and brand safety evaluation with collaborative calibration workflows. + +3. **Protocol-Level Capability Discovery** - `get_adcp_capabilities` task replaces agent card extensions, providing runtime discovery of agent capabilities, supported protocols, and geo targeting systems. + +4. **Creative Assignment Weighting** - Replace simple creative ID arrays with weighted assignments supporting granular placement control. + +5. **Geo Targeting Systems** - Structured geographic targeting with named systems (Nielsen DMA, UK ITL, etc.) for metros and postal areas. + +### Breaking Changes + +#### Media Channel Taxonomy + +The channel enum has been completely replaced with 19 planning-oriented channels that reflect how buyers allocate budgets: + +**Before (5 channels):** +```json +["display", "video", "audio", "native", "retail"] +``` + +**After (19 channels):** +```json +[ + "display", "olv", "social", "search", "ctv", "linear_tv", + "radio", "streaming_audio", "podcast", "dooh", "ooh", + "print", "cinema", "email", "gaming", "retail_media", + "influencer", "affiliate", "product_placement" +] +``` + +See the [Media Channel Taxonomy](/docs/reference/media-channel-taxonomy) for complete definitions and migration guidance. + +#### Creative Assignments with Weighting + +Replace `creative_ids` arrays with `creative_assignments` objects supporting optional weighting and placement targeting: + +**Before:** +```json +{ + "creative_ids": ["creative_1", "creative_2"] +} +``` + +**After:** +```json +{ + "creative_assignments": [ + { "creative_id": "creative_1", "weight": 60 }, + { "creative_id": "creative_2", "weight": 40, "placement_ids": ["homepage"] } + ] +} +``` + +Simple assignments still work: +```json +{ + "creative_assignments": [ + { "creative_id": "creative_1" }, + { "creative_id": "creative_2" } + ] +} +``` + +#### Geo Targeting with Named Systems + +Metro and postal targeting now require explicit system specification: + +**Before:** +```json +{ + "targeting": { + "geo_metros": ["501", "602"], + "geo_postal_codes": ["10001", "90210"] + } +} +``` + +**After:** +```json +{ + "targeting": { + "geo_metros": [ + { "system": "nielsen_dma", "code": "501" }, + { "system": "nielsen_dma", "code": "602" } + ], + "geo_postal_areas": [ + { "system": "us_zip", "code": "10001" }, + { "system": "us_zip", "code": "90210" } + ] + } +} +``` + +**Supported metro systems:** `nielsen_dma`, `uk_itl1`, `uk_itl2`, `eurostat_nuts2` + +**Supported postal systems:** `us_zip`, `gb_outward`, `gb_full`, `ca_fsa`, `de_plz`, `fr_code_postal`, `au_postcode` + +### New Features + +#### get_adcp_capabilities Task + +Protocol-level capability discovery replacing agent card extensions: + +```json +// Request +{ + "task": "get_adcp_capabilities" +} + +// Response +{ + "adcp": { + "major_versions": [3] + }, + "supported_protocols": ["media_buy", "signals", "governance"], + "extensions_supported": ["scope3", "garm"], + "media_buy": { + "features": ["inline_creative_management", "property_list_filtering"], + "portfolio": { + "publisher_domains": ["publisher.com"], + "channels": ["display", "ctv"], + "countries": ["US", "CA"] + }, + "execution": { + "targeting": { + "geo_metros": [{ "system": "nielsen_dma" }], + "geo_postal_areas": [{ "system": "us_zip" }] + } + } + } +} +``` + +#### Governance Protocol + +New protocol domain for brand safety and inventory curation: + +**Property Lists** - Managed lists of properties for targeting/exclusion: +- `create_property_list` - Create a new property list +- `get_property_list` - Retrieve with resolved properties +- `update_property_list` - Modify filters or sources +- `delete_property_list` - Remove a property list +- `list_property_lists` - Enumerate available lists + +**Content Standards** - Brand safety evaluation: +- `create_content_standards` - Define safety/suitability policies +- `get_content_standards` - Retrieve policy configuration +- `update_content_standards` - Modify policies +- `calibrate_content` - Collaborative dialogue to align on interpretation +- `validate_content_delivery` - Batch validate delivery records + +#### Unified Asset Discovery + +Formats now include a unified `assets` array with `required` boolean: + +**Before:** +```json +{ + "assets_required": ["main_image", "headline"] +} +``` + +**After:** +```json +{ + "assets": [ + { "asset_id": "main_image", "required": true }, + { "asset_id": "headline", "required": true }, + { "asset_id": "impression_tracker", "required": false } + ] +} +``` + +This enables buyers and AI agents to discover ALL assets a format supports, including optional ones. + +### Deprecations + +| Deprecated | Replacement | Removal | +|------------|-------------|---------| +| `adcp-extension.json` agent card | `get_adcp_capabilities` task | 4.0.0 | +| `list_property_features` task | `get_adcp_capabilities` governance section | 4.0.0 | +| `assets_required` in formats | `assets` array with `required` boolean | 4.0.0 | + +### Migration Checklist + +- [ ] Update channel enum values to new taxonomy +- [ ] Replace `creative_ids` with `creative_assignments` +- [ ] Add system specification to metro/postal targeting +- [ ] Switch from agent card extension to `get_adcp_capabilities` +- [ ] Update format parsing to use `assets` array +- [ ] Test governance protocol integration if using property lists + +--- + ## Version 2.5.0 **Released:** November 2025 | [Full Changelog](https://github.com/adcontextprotocol/adcp/blob/main/CHANGELOG.md#250)