Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/creative-delivery-contracts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"adcontextprotocol": minor
---

Add explicit creative delivery contracts for inline display tags, atomic paired redirects, and late-bound equivalent source representations. Define exact VAST asset versions versus product and seller acceptance sets, VAST MediaFile technical requirements, decimal file-size units, and declaration-level technical completeness. Add declared macro dialect, resolver ownership, encoding depth, capability matching, per-token validation results, deterministic selection lineage, structured rejection errors, documentation, and conformance vectors for issues #6761–#6764.
32 changes: 24 additions & 8 deletions dist/schemas/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,23 @@
"$id": "https://adcontextprotocol.org/schemas/index.json",
"title": "AdCP Schema Discovery",
"description": "Root discovery document for file-based AdCP schema consumers. Use latest_stable or a major/minor alias target instead of choosing by directory listing.",
"latest": "3.1.18",
"latest_stable": "3.1.18",
"latest": "3.1.19",
"latest_stable": "3.1.19",
"channel": "stable",
"aliases": {
"v3": "3.1.18",
"v3.1": "3.1.18",
"v3.0": "3.0.25",
"v3": "3.1.19",
"v3.1": "3.1.19",
"v3.0": "3.0.26",
"v2": "2.5.3",
"v2.5": "2.5.3"
},
"latest_by_major": {
"2": "2.5.3",
"3": "3.1.18"
"3": "3.1.19"
},
"latest_by_minor": {
"3.1": "3.1.18",
"3.0": "3.0.25",
"3.1": "3.1.19",
"3.0": "3.0.26",
"2.5": "2.5.3"
},
"versions": [
Expand Down Expand Up @@ -63,6 +63,14 @@
"path": "/schemas/3.2.0-beta.0/",
"index": "/schemas/3.2.0-beta.0/index.json"
},
{
"version": "3.1.19",
"stability": "stable",
"prerelease": false,
"deprecated": false,
"path": "/schemas/3.1.19/",
"index": "/schemas/3.1.19/index.json"
},
{
"version": "3.1.18",
"stability": "stable",
Expand Down Expand Up @@ -423,6 +431,14 @@
"path": "/schemas/3.1.0-beta.0/",
"index": "/schemas/3.1.0-beta.0/index.json"
},
{
"version": "3.0.26",
"stability": "stable",
"prerelease": false,
"deprecated": false,
"path": "/schemas/3.0.26/",
"index": "/schemas/3.0.26/index.json"
},
{
"version": "3.0.25",
"stability": "stable",
Expand Down
8 changes: 4 additions & 4 deletions dist/schemas/latest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"latest": "3.1.18",
"latest_stable": "3.1.18",
"latest": "3.1.19",
"latest_stable": "3.1.19",
"channel": "stable",
"path": "/schemas/3.1.18/",
"index": "/schemas/3.1.18/index.json"
"path": "/schemas/3.1.19/",
"index": "/schemas/3.1.19/index.json"
}
1 change: 1 addition & 0 deletions docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@
"docs/creative/sales-agent-creative-capabilities",
"docs/creative/multi-agent-orchestration",
"docs/creative/creative-manifests",
"docs/creative/delivery-variants",
"docs/creative/private-assets",
"docs/creative/buyer-attached-inputs"
]
Expand Down
2 changes: 1 addition & 1 deletion docs/contributing/x-entity-annotation.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ High-level groupings (see the registry for full descriptions). *Categories below
| Brand & rights | `advertiser_brand`, `rights_holder_brand`, `rights_grant` |
| Account & party | `account`, `operator` |
| Media buy | `media_buy`, `package`, `product`, `proposal`, `product_pricing_option`, `spot_airing` |
| Creative | `creative`, `creative_format` |
| Creative | `creative`, `creative_source_revision`, `creative_delivery_variant`, `creative_locale_variant`, `creative_format`, `build_variant` |
| Data & targeting | `audience`, `audience_evidence`, `audience_evidence_snapshot`, `signal`, `signal_activation_id`, `demographic_interval_id`, `event_source` |
| Lists & catalogs | `collection_list`, `property_list`, `catalog`, `catalog_generation`, `catalog_item`, `property` |
| Plans & governance | `media_plan`, `governance_plan`, `governance_registry_policy`, `governance_inline_policy`, `governance_check`, `governance_delivery_statement`, `governance_delivery_observation`, `governance_outcome`, `governance_adjustment`, `governance_adjustment_evidence`, `seller_adjustment`, `content_standards`, `task`, `attestation_credential` |
Expand Down
30 changes: 25 additions & 5 deletions docs/creative/asset-types.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ For payload schemas (the structure of the actual asset data supplied in creative
- `duration_ms` (when applicable)
- `format` (declared container type)

File-size limits use decimal, exact units throughout AdCP: `*_kb` means 1 KB = 1,000 bytes, `*_mb` means 1 MB = 1,000,000 bytes, and `*_bytes` is an exact byte count. Do not interpret KB/MB fields as KiB/MiB.

## Asset Type Schema

The official JSON schema for asset types is available at:
Expand Down Expand Up @@ -97,7 +99,7 @@ Video assets represent video files with specific technical requirements.
- `acceptable_codecs`: Video codecs (h264, h265, vp8, vp9, av1)
- `acceptable_resolutions`: List of width x height strings
- `aspect_ratio`: Required aspect ratio (16:9, 9:16, 1:1, etc.)
- `max_file_size_mb`: Maximum file size in megabytes
- `max_file_size_mb`: Maximum file size in decimal megabytes (1 MB = 1,000,000 bytes)
- `min_bitrate_mbps` / `max_bitrate_mbps`: Bitrate range in Mbps
- `features`: Additional requirements (e.g., ["non-skippable", "sound on"])

Expand All @@ -123,7 +125,7 @@ Static image assets for banners, logos, and visual content.
- `min_width` / `min_height`: Minimum dimensions (px; typically used by responsive/sizeless formats)
- `aspect_ratio`: Required aspect ratio
- `acceptable_formats`: Image formats (jpg, png, gif, webp, svg)
- `max_file_size_kb`: Maximum file size in kilobytes
- `max_file_size_kb`: Maximum file size in decimal kilobytes (1 KB = 1,000 bytes)
- `transparency`: Whether transparency is required/supported
- `animation_allowed`: Whether animated GIFs are accepted
- `notes`: Additional requirements (e.g., "Must be free of text")
Expand Down Expand Up @@ -175,6 +177,7 @@ Senders **SHOULD** include `url_type` on every URL asset. The valid values are:
| Value | Mechanism |
|---|---|
| `clickthrough` | User-click destination (landing page or ad-tech redirector) |
| `ad_request` | Invokes a third-party display creative endpoint at impression time |
| `tracker_pixel` | Fires HTTP GET, expects 1×1 pixel or 204 response (impression / event / 3P trackers) |
| `tracker_script` | Loads as a `<script>` tag — measurement SDKs (OMID verification, native event trackers using `method: 2`) |

Expand All @@ -197,6 +200,8 @@ If `url_type` is **absent**, receivers SHOULD fall back to the format's `url-ass
| `viewability_tracker` | `tracker_script` — OMID and equivalent verification SDKs **require** a `<script>` tag; firing them as a pixel produces no measurement |
| `third_party_tracker` | **No safe fallback.** Mechanism is integration-specific (DV/IAS ship both pixel and script forms). Receivers MAY reject or warn. |

Display ad-request URLs also have no role-based fallback. Declare `url_type: "ad_request"` explicitly.

If neither `url_type` nor a format-side `role` is available, receivers MUST NOT silently pick a mechanism — firing a clickthrough URL as a pixel (or vice versa) silently corrupts measurement and breaks the user flow. Receivers SHOULD reject the manifest.

> **VAST/DAAST URLs are not URL assets.** A URL pointing to ad-server XML markup is parsed, not GET-fired. Use `asset_type: "vast"` with `delivery_type: "url"` for VAST tags, and the dedicated tracker types (`vast_tracker` / `daast_tracker`) once those land per [RFC #2915](https://github.com/adcontextprotocol/adcp/issues/2915). A VAST tag declared as `asset_type: "url"` with `url_type: "tracker_pixel"` is non-conformant under these mechanism semantics.
Expand Down Expand Up @@ -249,12 +254,12 @@ Audio files for audio ads and podcasts.
- `duration_seconds`: Expected duration
- `acceptable_formats`: Audio formats (mp3, m4a, aac, ogg)
- `min_bitrate_kbps`: Minimum bitrate in kilobits per second
- `max_file_size_mb`: Maximum file size in megabytes
- `max_file_size_mb`: Maximum file size in decimal megabytes (1 MB = 1,000,000 bytes)
- `stereo_required`: Whether stereo audio is required

### HTML Asset

HTML5 creative assets for rich media formats and third-party display tags.
Inline HTML content assets. Seller-hosted HTML5 creative bundles use a `zip` asset. Third-party display markup uses the `display_tag` asset below.

```json
{
Expand All @@ -276,6 +281,21 @@ HTML5 creative assets for rich media formats and third-party display tags.
- `allowed_features`: Allowed HTML5 features
- `restricted_features`: Features that must not be used

### Display Tag Asset

An atomic third-party display representation. `delivery_type` is one of `tag_url`, `inline_markup`, or `paired_redirect`. The paired form requires both `ad_request_url` and `clickthrough_url`; they cannot be trafficked or revised independently.

```json
{
"asset_type": "display_tag",
"delivery_type": "paired_redirect",
"ad_request_url": "https://ads.acme-example.com/ad?slot=42",
"clickthrough_url": "https://click.acme-example.com/redirect"
}
```

Inline markup also records `markup_type` as `iframe_javascript`, `javascript`, or `standard`. Preserve markup bytes exactly. Do not classify it as `html5`, which means a seller-hosted zip bundle.

### VAST Asset

VAST (Video Ad Serving Template) tags for third-party video ad serving.
Expand Down Expand Up @@ -308,7 +328,7 @@ VAST (Video Ad Serving Template) tags for third-party video ad serving.
- `delivery_type`: "url" or "inline" (required discriminator)
- `url`: URL endpoint that returns VAST XML (required when delivery_type is "url")
- `content`: Inline VAST XML content (required when delivery_type is "inline")
- `vast_version`: VAST specification version (2.0, 3.0, 4.0, 4.1, 4.2, 4.3)
- `vast_version`: Exact VAST specification version supplied by this asset (2.0, 3.0, 4.0, 4.1, 4.2, 4.3). Product format options use plural `vast_versions` for their accepted set.
- `vpaid_enabled`: Whether VPAID (Video Player-Ad Interface Definition) is supported
- `max_wrapper_depth`: Maximum allowed wrapper/redirect depth
- `duration_ms`: Expected video duration in milliseconds (if known)
Expand Down
14 changes: 13 additions & 1 deletion docs/creative/canonical-formats.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ Downstream platform authorization is separate from production source. If a forma

When `asset_source` is `buyer_uploaded`, the buyer ships rendered assets and any tracker URLs attached to those assets are buyer-controlled (universal_macros for impression/click; `vast_tracker` / `daast_tracker` assets for decomposed VAST/DAAST trackers). When `asset_source` is any of the seller-rendered values (`seller_pre_rendered_from_brief`, `seller_human_designed`, `agent_synthesized`) or `publisher_host_recorded`, the buyer never sees the rendered artifact directly. Two normative paths apply:

- **Macro-substituted tracking (default).** The seller honors AdCP universal_macros at impression time — `{IMPRESSION_TRACKER}`, `{CLICK_TRACKER}`, etc. — and substitutes buyer-supplied tracker URLs (declared on the manifest's optional `landing_page_url` and the buyer's measurement-vendor pixels declared via `platform_extensions` on the format, filtered by `extensions[uri].extends === "tracking"`) into the rendered creative's serving template. The buyer registers their measurement pixels client-side; the seller calls them at serve time. This is the dominant path for image / video / audio production where serving and tracking are decoupled.
- **Capability-gated macro-substituted tracking.** Tracker URLs are explicit `pixel_tracker`, `vast_tracker`, or `daast_tracker` assets (or governed tracking extensions); `landing_page_url` remains the navigated destination, not a tracker. Exact macro capabilities declare whether occurrences such as `{IMPRESSION_ID}` and `{CACHEBUSTER}` can be processed, but they do not claim that the product accepts or fires the containing tracker. When the product tracking contract declares the asset type honored, the seller embeds and fires it according to that commitment. Until that contract is present, tracker acceptance and firing are undeclared and buyers MUST NOT infer them from macro compatibility.
- **Sync-creatives tracker block.** For products where the seller produces a serving artifact that embeds tracker URLs directly (e.g., a generated VAST tag or a stitched companion banner), the seller's `sync_creatives` response SHOULD include a `tracker_block` field listing the impression URL pattern and click URL pattern. Buyers register those with their measurement vendor at sync time. This path covers the generative-DSP pattern where the serving artifact and the tracking shape are produced together.

`vast_tracker` and `daast_tracker` decomposed tracker assets work for both `buyer_uploaded` and seller-rendered sources — when the seller renders, those tracker assets are inputs to the rendered tag, attached to the appropriate VAST/DAAST `<TrackingEvents>` block at production time. When the buyer ships a complete `vast` or `daast` tag, the trackers travel inside the tag.
Expand Down Expand Up @@ -346,6 +346,18 @@ Do not use “renderer” for all three roles; it hides the trust and routing bo

Creative declarations describe structural production and acceptance constraints. Price, floor, availability, auction mechanics, and deal eligibility remain product or pricing facts; copying them into format parameters would create multiple authorities for the same commercial term.

### Technical completeness and file-size units

Technical constraints are explicit; canonical prose, examples, common practice, and implementation defaults are never hidden acceptance requirements. For every applicable product, publisher, and placement declaration:

- `technical_requirements_complete: true` means the declaration enumerates every technical creative-acceptance constraint within that layer's authority. An omitted technical field means no constraint at that layer.
- `technical_requirements_complete: false`, or omission of the assertion, means omitted technical fields are undeclared. Omission means neither “supported” nor “no constraint,” and consumers MUST NOT infer a value.
- The resolved product/placement contract is complete only when every applicable declaration layer asserts `technical_requirements_complete: true`. A seller making that effective assertion commits that a creative satisfying the published technical contract will not later be rejected for an undisclosed technical constraint.

Completeness is not general creative approval. Policy, legal, security, malware, transport/fetch failure, corrupt bytes, or a material mismatch between declared metadata and inspected content can still cause rejection. For custom formats and platform extensions, a completeness assertion includes the technical constraints in the referenced schema artifacts.

Creative file-size units are decimal and exact throughout AdCP: a field ending in `_kb` uses **1 KB = 1,000 bytes**, a field ending in `_mb` uses **1 MB = 1,000,000 bytes**, and a field ending in `_bytes` is an exact byte count. Implementations MUST NOT substitute binary KiB/MiB units for these fields.

Classification follows the buyer deliverable and who renders it, not the behavioral richness of the placement. For example, a buyer-uploaded MP4 in a docking player is `video_hosted`; an opaque third-party tag that produces the same experience is `display_tag`. Maintainers and catalog encoders can verify these boundaries against the [AdCP 3.2 classification vectors](https://github.com/adcontextprotocol/adcp/blob/main/static/test-vectors/canonical-format-classification.json).

A publisher declares the format contract and enough production semantics for a buyer to know what it must supply: canonical kind, parameter constraints, slots, asset source, composition model, and required connections. It does **not** maintain a vendor list of every creative agent capable of producing that contract. Creative agents self-declare compatibility.
Expand Down
78 changes: 74 additions & 4 deletions docs/creative/channels/display.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -60,22 +60,92 @@ Use min/max width and height for a genuinely responsive envelope. Exact-size, mu

## HTML5 and third-party tags

`html5` describes a buyer-supplied HTML bundle. `display_tag` describes externally served HTML or JavaScript markup. Keep them separate because validation, hosting, security, and measurement differ.
`html5` describes a buyer-supplied zip bundle that the seller hosts. `display_tag` describes a third-party-served representation. Keep them separate because validation, hosting, security, and measurement differ. Inline third-party markup is never an `html5` bundle.

Display tags have three delivery variants:

| Variant | Asset contract |
|---|---|
| `tag_url` | One `url` asset with `url_type: "ad_request"`, or a `display_tag` asset with `delivery_type: "tag_url"` |
| `inline_markup` | One `display_tag` asset with byte-preserved markup and its markup type |
| `paired_redirect` | One `display_tag` asset containing both `ad_request_url` and `clickthrough_url` |

The existing `tag_url` slot remains the backward-compatible default. A seller accepting inline or paired delivery publishes an explicit option with a `display_tag` slot.

### Inline iframe/JavaScript

```json
{
"format_option_id": "inline_iframe_javascript_300x250",
"format_kind": "display_tag",
"params": {
"width": 300,
"height": 250,
"supported_delivery_variants": ["inline_markup"],
"slots": [
{ "asset_group_id": "serving_tag", "asset_type": "html", "required": true },
{ "asset_group_id": "impression_tracker", "asset_type": "pixel_tracker", "required": false }
{ "asset_group_id": "serving_tag", "asset_type": "display_tag", "required": true }
]
}
}
```

```json
{
"format_kind": "display_tag",
"format_option_ref": {
"scope": "product",
"format_option_id": "inline_iframe_javascript_300x250"
},
"assets": {
"serving_tag": {
"asset_type": "display_tag",
"delivery_type": "inline_markup",
"markup_type": "iframe_javascript",
"markup": "<iframe src=\"https://ads.acme-example.com/render?cb=%%CACHEBUSTER%%\"></iframe>"
}
}
}
```

### Internal Redirect

A two-URL internal redirect is represented portably as `paired_redirect`; the canonical kind remains `display_tag`. The asset is atomic so its two URLs cannot be mixed across rows or revisions.

```json
{
"format_option_id": "gam_internal_redirect",
"format_kind": "display_tag",
"params": {
"width": 300,
"height": 250,
"supported_delivery_variants": ["paired_redirect"],
"slots": [
{ "asset_group_id": "serving_tag", "asset_type": "display_tag", "required": true }
]
}
}
```

```json
{
"format_kind": "display_tag",
"format_option_ref": {
"scope": "product",
"format_option_id": "gam_internal_redirect"
},
"assets": {
"serving_tag": {
"asset_type": "display_tag",
"delivery_type": "paired_redirect",
"ad_request_url": "https://ads.acme-example.com/ad?slot=42&cb=%%CACHEBUSTER%%",
"clickthrough_url": "https://click.acme-example.com/redirect?dest=%%DEST_URL_ESC%%"
}
}
}
```

Both fields are required by schema. A half-present pair is invalid. Do not split the pair into independent URL slots.

Buyers discover seller acceptance from `Product.format_options[]`. Creative agents that can build or validate these contracts advertise matching `creative.supported_formats[]` entries.

See [Canonical formats](/docs/creative/canonical-formats), [Creative manifests](/docs/creative/creative-manifests), and [Universal macros](/docs/creative/universal-macros).
See [Creative delivery variants](/docs/creative/delivery-variants), [Canonical formats](/docs/creative/canonical-formats), [Creative manifests](/docs/creative/creative-manifests), and [Universal macros](/docs/creative/universal-macros).
Loading
Loading