You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
RFC: Creative Formats v2 — canonical formats with tracking baked in, product-bound variants, validate_input
Type: RFC / major additive feature Severity: high (sets the direction for creative format authoring across 3.x) Target: 3.1 preview track; stabilize through 3.2/3.3; v1 named-format model deprecation continues into 4.x with full removal at 5.0
Supersedes: #3269 (canonical asset_id slot vocabulary), #3270 (output-validation handshake) Adjacent: #3268 (PreviewCreativeResponse single-render hoist) — separate but coordinated, ships 3.1 First implementation: #3307 (Phase 1 + Phase 2 preview branch)
Revision history:
r2 (2026-04-26): Incorporated 3-expert-review feedback (synthesis): canonical IS the contract; sponsored_placement split 3-way; nondeterminism gap explicit; digest pinning; build_creative typed inputs.
r3 (2026-04-26): Working-example walkthrough refinements: tracking baked into each canonical format (not separated); split image / html5 / display_tag and video_hosted / video_vast and audio_hosted / audio_daast because tracking models are fundamentally different per format; format keyed by canonical name (drop discriminator); platform extensions distributed via URI+digest bundled in get_products.
r4 (2026-04-27): Three more simplifications from end-to-end walkthrough.
build_capability and build_capability_ref dissolved into inputs directly on the format declaration. External creative agents are invisible to the buyer in the typical case (sales agent is typically the creative agent, or seller calls upstream agent internally — buyer-seller boundary is the only protocol relationship).
creative.creative_build_capabilities renamed to creative.supported_formats on get_adcp_capabilities. Drops "build_" framing on the discovery surface; uses ProductFormatDeclaration shape (one primitive, two homes — sales-side inline on products, creative-agent-side as supported_formats list).
asset_group_id field added to format.json slot declarations as a v1↔v2 migration bridge. Lets v1 reference creatives declare their canonical equivalents inline (e.g., slot click_url → asset_group_id: "landing_page_url").
Plus: vocabulary aliases expanded for common slots (audit-grounded); Phase 1 zip asset type replaced the earlier delivery_type addition on html/javascript (URL-delivered HTML/JS routes through url-asset; HTML5 zip bundles get a proper first-class asset type).
Sales agents do NOT expose build_creative — that's a creative-agent surface only. Creative agents may also expose sync_creatives (for ad server use cases). Both roles provide preview_creative. The two flows for inputs-driven creative: Flow 1 — buyer pre-produces via a creative agent's build_creative and submits the rendered manifest via sync_creatives to the seller. Flow 2 — buyer submits inputs directly via sync_creatives and the seller produces internally.
Problem
Today's creative format model has friction adopters hit on day one, plus an architectural drift that produced most of that friction:
No explicit "format master" role. Formats are entities in a registry separate from products. Sellers maintain platform-specific format names (meta_reels, tiktok_in_feed_video, spotify_audio_standard) that are really product-variant declarations. The split forces sellers to author and maintain duplicate metadata and obscures what's universal vs platform-specific.
Format asset_id slots are author-invented strings. Every adopter picks script or body or text for "the spoken script body of an audio ad." Asset-group canonical vocabulary exists for catalogs but isn't reused at the format slot level.
format_id is a compound { agent_url, id } object where the name promises a string. Can't be used as a map key. SDK codegen exposes object lookups instead of typed accessors. No content-digest pinning means third-party agents can mutate format definitions mid-flight.
No protocol-level handshake for input validation. Creative-template platforms whose output isn't deterministically format-compliant from inputs alone have no clean rejection path.
Generative formats proliferate. Every social/search/UA platform has 3-7 *_generated_* formats today. Most are structurally creative_brief + <reference shape>.
promoted_offerings formats duplicated across 8 of 12 platforms with identical internal creative shape.
Pure-catalog and AI-surface formats (Amazon SP, Pinterest Collection, Google PMax, ChatGPT-style brand mentions) have no buyer creative slots — they're surface-composed. Modeling as formats with empty creative shapes is awkward; lumping them into one cluster also wrong.
Six different field names for "destination URL" today: click_url, link, final_url, link_url, landing_page_url, click_through_url.
Tracking is mistakenly treated as cross-cutting platform metadata. It's actually format-specific: VAST tracking is the VAST spec; HTML5 tracking is MRAID + OM-SDK; image tracking is impression pixel + click URL. These don't vary platform to platform — they vary format to format. Lumping image | html | javascript under one canonical hides this; treating tracking as a platform-level extension creates needless indirection.
Empirical input
Three audits drove this RFC:
Social/retail platform formats: 12 platforms, 86 ad formats. ~76% fit a small canonical format set; remaining ~24% platform-specific (catalog-driven retail media, dynamic profile-data, multi-page story, interactive quiz, lead-form, message/InMail, sponsored chat).
Tag handling in social/retail: zero hits across all 12 social/retail adapters for vast, daast, html5, iframe, display_tag. Walled-garden hosted assets only.
Tag handling in publisher-direct (GAM via prebid salesagent): maps to ThirdPartyCreative, CustomCreative, ImageRedirectCreative/VideoRedirectCreative, TemplateCreative (native). Wire format already accepts AdCP delivery_type: url|inline.
Adopter signal: AudioStack @adcp/client v6.0 be-Emma test surfaced #3268, #3269, #3270 in a single round.
Goals
AdCP defines canonical formats; sellers' products narrow them. Canonical format is the buyer's stable contract. Products narrow it via inline ProductFormatDeclaration carrying parameters and platform extensions; they don't replace it.
Tracking and measurement are baked into each canonical format, not abstracted into platform extensions. A canonical's tracking events, macro substitutions, click handling, and measurement integrations are part of its schema.
Format slot names draw from a canonical, governed vocabulary (asset_group_id).
format_id is a string; canonical formats have short canonical names. URI form (creative-agent capabilities and third-party formats) is content-digest-pinned.
Surface a clean input-validation primitive (validate_input), with explicit handling for nondeterministic generative platforms.
Generative formats are build_creative capabilities targeting canonical formats. Inputs are a typed vocabulary.
SDK codegen of canonical formats and canonical patterns; platform extensions distributed via URI+digest bundled in get_products.
Brand identity is implicit context via brand.json, with brand_kit_override for the missing/stale case.
Non-goals
Forcing named-format dissolution. v2 product-bound declarations are opt-in. v1 named formats remain a first-class path indefinitely.
Designing native canonical format without first auditing TemplateCreative + OpenRTB Native 1.2 — see Phase gating.
Designing the AI mediation protocol (third part of SI's decomposition — see §2).
output_modality declaration (deferred until text/audio AI-surface formats need it).
Schema strategy
v2 ships side-by-side with v1 in the existing v3 namespace.
Modified backwards-compatibly:html-asset.json and javascript-asset.json add optional delivery_type: "url" | "inline" (✅ #3307). product.json adds optional format field carrying v2 ProductFormatDeclaration.
Net-new v2 schemas: canonical format definitions (11) + _base.json with shared parameters including inputs, product-format-declaration.json, asset-group-vocabulary.json (✅), scenes.json (✅), zip-asset.json (✅), platform-extension-ref.json, validate-input-{request,response,result}.json. Note:build-capability.json, build-capability-ref.json, list-build-capabilities-*.json from earlier revisions were dropped in r4 — input contract folds into the format declaration; creative-agent capability discovery folds into creative.supported_formats on get_adcp_capabilities. Canonical-pattern schemas for cta_vocabulary / destination_kinds / brand_safety / universal_macros were dropped earlier (vocabularies stay where they already live; tracking is baked into formats).
Version discrimination: A given product is either v1 (references a separately-defined format by format_id) or v2 (carries its format declaration inline). Sellers can publish both during transition.
Design
1. Architectural framing — three layers
Canonical formats (11) — AdCP-defined universal building blocks. The canonical format itself is the buyer's contract. Same as OpenRTB and VAST treat creative format: a stable reference buyers validate against before knowing which seller wins. Each canonical bakes in its tracking events, macro substitutions, click handling, measurement integrations — because tracking is format-specific, not platform-specific.
Canonical patterns — cross-format shared concerns published by AAO, compiled into SDKs. Smaller set than I originally drafted: cta_vocabulary, destination_kinds, brand_safety_frameworks, universal_macros. Tracking is not a canonical pattern — it lives in the canonical format that owns it.
Platform extensions — narrow, truly platform-specific additions. Pixel ID formats (Meta vs TikTok vs Google), conversion event taxonomies, platform-specific CTA additions (Meta WATCH_MORE), platform-specific destinations (Meta messenger_thread, whatsapp_phone). Distributed via URI+digest, bundled in get_products responses (see §5c).
2. The 11 canonical formats
Split by tracking/measurement model (because tracking is fundamentally different per format) plus output shape.
Buyer asset pool, surface composes combinations (Google Responsive Display/Search Ads, Performance Max, Demand Gen; Meta Advantage+ creative). Industry term: "Responsive" (Google) / "Advantage+ creative" (Meta).
Per-asset performance breakdown by surface
agent_placement
Sponsored placement composed by an AI surface in response to a user query (ChatGPT, Perplexity, voice assistants, sponsored search snippets). Distinct from si_chat (brand-owned conversation; user → brand's agent — different protocol layer). Parallels sponsored_placement structurally; both surface-composed, differ by surface type.
Mention-level impression + attribution
Each canonical format's schema declares:
Slot vocabulary drawn from canonical asset_group_id registry (or format-specific where role doesn't generalize)
Parameter shape (dimensions, duration, file size, codec, character limits)
Tracking events the format emits and their substitution patterns (referencing universal_macros)
Click handling and destination resolution (referencing destination_kinds)
Measurement integrations the format supports (OM-SDK, MRAID, VAST events, etc.)
composition_model: deterministic | algorithmic — explicit field; sponsored_placement is deterministic, responsive_creative and agent_placement are algorithmic
provenance_required?: boolean — optional flag for brand-safety-sensitive products to refuse unsigned synthesized assets (C2PA hooks)
Sponsored placement and the SI architectural decomposition
The three sponsored canonicals (sponsored_placement, responsive_creative, agent_placement) cover part 1 of three architecturally distinct patterns currently conflated under "Sponsored Intelligence":
Chat with advertiser — user converses directly with the brand's SI agent. Out of scope; existing SI agent track.
AI mediation — surface (ChatGPT, Perplexity) discovers/selects/routes between advertisers. Out of scope; needs its own RFC track.
v2 ships #1 inside the canonical format catalog. The other two stay on their respective tracks.
3. Product format declarations — keyed by canonical name
A v2 product carries its format declaration inline, keyed by canonical format name:
interfaceProduct{product_id: string;// ... existing product fields ...format?: {[CanonicalFormatId]: ProductFormatParameters&{cta?: CtaPatternRef;destinations?: DestinationKindsRef;brand_safety?: BrandSafetyFrameworkRef;tracking?: TrackingExtensions;composition_model?: 'deterministic'|'algorithmic';provenance_required?: boolean;platform_extensions?: ExtensionRef[];inputs?: InputsContract;// r4: what the format requires from the buyer; lives directly on the formatproduction_window_business_days?: number;// r4: production turnaround when format requires agent production};};// r4: build_capability_ref dropped — external creative agent relationships are invisible to the buyer}
The format key (image, video_vast, audio_hosted, etc.) IS the format declaration. SDKs codegen CanonicalFormats.image({...}) accessors matching exactly. No canonical discriminator field needed — the key is the discriminator.
A product can carry exactly one format key; validators enforce this.
Worked example — Meta Reels (video_hosted narrowed)
The video_hosted canonical format already declares OM-SDK measurement, external impression/click/quartile trackers, and macro substitution patterns ({CACHEBUSTER}, {CLICK_URL}, {OFFERING_ID} etc. from universal_macros). Meta's product narrows duration, dimensions, slot character limits, and references its specific extensions for pixel ID and Reels placement. The buyer sees "video_hosted with these constraints + Meta's extensions" rather than a sea of separately-declared concerns.
Worked example — IAB MREC (image narrowed, multi-seller standard)
The image canonical format already declares impression pixel + click URL + optional viewability pixel; NYTimes's product narrows the dimensions to MREC, file size, image formats, and references its strict OM extension. Buyers can validate a manifest against canonical image BEFORE knowing which publisher wins — every IAB MREC product across publishers narrows the same canonical with similar parameters. That's the canonical-as-contract value.
For HTML5 banners on the same placement, the seller publishes a separate product:
The html5 canonical format declares MRAID + OM-SDK + click-tag macro + backup image as part of its tracking spec. NYTimes narrows the dimensions, file size limits, and animation constraints. Different format from image because the tracking model is fundamentally different.
Worked example — Podcast 30s host-read (audio_hosted with inline inputs)
Host-reads are the host-recorded-from-buyer-script pattern. The buyer doesn't ship audio — they supply a script and the publisher's host records the audio. The format declaration carries the input contract directly; no separate capability lookup needed.
Two flows depending on whether the buyer pre-produces or the seller produces internally:
Flow 1 — buyer pre-produces. Buyer reads the format → calls build_creative({ format: <The Daily's audio_hosted narrowing>, inputs: { script, brand } }) on a creative agent (could be The Daily's own creative-agent surface, the buyer's in-house studio, AudioStack-style services — any agent that lists this format under creative.supported_formats on get_adcp_capabilities) → receives rendered manifest → submits via sync_creatives to The Daily's sales agent.
Flow 2 — seller produces internally. Buyer reads the same format → submits via sync_creatives with the inputs directly → seller produces internally (host records, calls upstream creative agent, whatever) → returns async status; buyer polls or waits for completion.
The format's audio_source and buyer_audio_acceptance parameters tell the buyer which flows are accepted. Both flows are valid for The Daily's host-read because the publisher's host MUST be the producer in either case — the difference is whether the buyer drives the build call or the seller drives it. Other products might accept Flow 1 only or Flow 2 only.
Verbatim host-reads use script; talking-points host-reads use creative_brief. Same target format; different input contract. The format itself encodes which is needed.
Sales agents do not expose build_creative
build_creative is a creative-agent surface only. Sales agents expose get_products and sync_creatives. Creative agents may also expose sync_creatives for the ad server use case (an agent can act as both a creative agent for build flows and an ad server for delivery). Both roles provide preview_creative. The creative.supported_formats field on get_adcp_capabilities is what creative agents declare; it uses the same ProductFormatDeclaration shape as products' inline format.
4. format_id as URI string with content-digest pinning
v2 format_id is a string. Three valid forms:
Canonical reference: format_id: "video_hosted" — bare token, resolves to AAO canonical.
Product reference: product_id is the seller-side identity; the product's format declaration is the source of truth for that variant.
URI form for creative-agent capabilities and third-party formats: format_id: "https://creative.audiostack.com/adcp#audio_30s". Pinned via content digest.
Content-digest pinning (required for URI form): Buyers SHOULD include format_digest: "sha256:...". Agents MUST publish digests. Mid-flight format-definition mutation breaks the digest match; buyers detect drift before validating against a stale shape. Same model as TMP schema-pinning; addresses #2335.
For canonical AAO formats, SDKs ship the catalog with versioned digests at well-known paths.
5. Canonical asset_group_id vocabulary (✅ shipped in #3307)
Format slot names draw from a governed vocabulary. ✅ Shipped: 7 catalog vocab entries + 12 audit-driven additions in static/schemas/source/core/asset-group-vocabulary.json. Includes landing_page_url canonicalizing 6 v1 alias names.
{CACHEBUSTER}, {CLICK_URL}, {OFFERING_ID}, {MEDIA_BUY_ID}, {CREATIVE_ID} etc.
Tracking endpoints across all formats
Tracking is not a canonical pattern. Each canonical format declares its own tracking events; they reference universal_macros for substitution. That's the only cross-format tracking concept.
5c. Platform extensions — distribution and discovery
Platform extensions are narrow, truly platform-specific additions to canonical patterns or canonical format slots. Examples:
meta_pixel — extends tracking slots on most formats: adds pixel_id, conversion_event enum
Each extension's response carries: extension schema (which fields it adds), the canonical pattern or slot it extends, version, and content digest.
How buyers get them: bundled in get_products. The sales agent's response includes definitions for any extension referenced by any product in the response:
Buyer's SDK caches by URI@digest. Subsequent get_products responses reference by digest; if buyer already has the extension cached, the inline definition is omitted.
Direct URI fetch fallback (GET https://meta.adcp/extensions/meta_pixel) is supported for tooling/debugging but the primary path is bundled-in-get_products.
Why this works:
No extra round trips
Cacheable across products that share extensions (Meta has 50 products referencing meta_pixel; buyer fetches once)
Digest-pinned (no silent drift)
Owned by the right party (Meta's agent is authoritative for Meta's extensions)
No central registry needed; each platform is its own canonical source
6. Brand context via brand.json with explicit override
When a manifest carries brand: { domain: "acme.com" }, the seller pulls brand context from brand.json. Override path for missing/stale brand.json:
Deterministic platforms: validate predictively, reject the input. predicted carries the platform's estimate.
Nondeterministic platforms (Veo, Sora, Runway-class): predictive validation is a category error. Two protocol obligations:
Platform MUST run its own post-synthesis QA loop and surface only validated outputs.
If exhausted without a valid artifact, return task_failed with structured synthesis_failed reason carrying constraints unmet, attempts, suggested adjustments.
8. preview_creative updates
Single tool, response shape adapts. #3268 single-render hoist applies for direct mode; nested previews[] for multi-render. New optional preview_subset_ids?: string[].
9. build_creative — generative as capability with typed inputs
build_creative({format_id: string,// canonical the output must satisfyinputs: BuildCreativeInputs,// typed vocabularybrand?: {domain: string}})→CreativeManifest
BuildCreativeInputs is a typed map (see §5 vocabulary). Different generative shapes use different combinations. Calls validate_input internally on produced manifest.
10. SDK codegen + canonical catalog distribution
Compiled into SDKs:
11 canonical format definitions (with their tracking specs)
Type-safe parameterization, IDE autocomplete on canonical asset_group_id slot names, version-pinned canonical catalog (digest mismatch detectable), local validation without network.
Codegen scaffolding ships in 3.1 (preview); stable for TypeScript and Python in 3.2.
11. Discovery surfaces by agent role; list_creative_formats deprecated and back-compat-wrapped
Sales agents: get_products is the v2 discovery surface for product-bound formats. Bundles platform extensions inline.
Creative agents: declare which canonical formats they can build via creative.supported_formats on get_adcp_capabilities. Each entry uses the same ProductFormatDeclaration shape as products' inline format — keyed by canonical name with parameters and inputs. Creative agents may also expose sync_creatives for ad-server use cases.
Deprecation timeline (revised): v1 list_creative_formats deprecated in 3.x but functional through 4.0; sellers SHOULD provide server-side flatten wrappers that derive v1 shape from v2 product format declarations. Removed at 5.0.
schemas/v3/formats/canonical/{image,html5,display_tag,image_carousel,video_hosted,video_vast,audio_hosted,audio_daast,sponsored_placement,responsive_creative,agent_placement}.json plus _base.json with shared parameter fields including inputs and production_window_business_days
creative.supported_formats field added to get_adcp_capabilities response (creative-agent discovery)
format.json slot declarations (Individual* and Group*) gain optional asset_group_id field for v1↔v2 migration bridge
product.json adds optional format field; creative-manifest.json adds optional brand and brand_kit_override
What dissolves
composition: 'slot_fill' | 'surface_composed' — derivable from canonical declaration.
expansion: 'per_offering' | 'per_item' — derivable from field_bindings shape.
output_modality — derivable from canonical's output asset_type.
promoted_offerings campaign mode — collapses into product format declarations + field_bindings.
Generative as a format family — build_creative capability with typed inputs.
Brand identity slots — implicit context via brand.json + brand_kit_override.
list_creative_formats as a single tool — split by agent role.
Tracking as a separate canonical pattern — baked into each canonical format.
canonical discriminator field — replaced by format-keyed-by-name.
iab_size redundant labeling — derive from dimensions.
Polymorphic asset_types within image/video/audio — split by tracking model into separate canonicals.
build_capability and build_capability_ref as separate concepts (r4) — collapsed into inputs directly on the format declaration. External creative agents are invisible to the buyer; supply-chain relationships stay off the protocol surface.
creative_build_capabilities field name (r4) — renamed to creative.supported_formats; same ProductFormatDeclaration shape as products' inline format. One primitive, two homes.
Sales-agent build_creative exposure (r4) — build_creative is a creative-agent surface only. Sales agents expose get_products and sync_creatives; creative agents may also expose sync_creatives for ad-server use cases.
delivery_type as a discriminator on html-asset.json/javascript-asset.json (Phase 1 scrub) — URL-delivered HTML/JS routes through url-asset.json with appropriate url_type; HTML5 zip bundles get a proper first-class zip asset type.
What does not dissolve:
Named platform-specific formats as a v1-era pattern — they keep working through 3.x/4.x. v2 is the new path; sellers migrate when their organizational reality permits.
Migration
Realistic adoption by adopter type:
Adopter
Cost
Realistic timeline
Notes
DSP buyer agents (TTD-shaped)
Low
3.1-3.2
Reading inline product format declarations is strictly easier than v1 cross-reference.
Multi-team metadata ownership, legal review on format changes. Realistic only when AAO ships a translator from existing format docs to v2 declarations.
Creative agents (AudioStack-shaped)
Low, high motivation
3.1-3.2
creative.supported_formats matches what they want to declare.
Publisher direct (GAM/prebid path)
Medium
Blocked on native pre-audit
Native shapes are a major adoption driver.
Phase
What ships
3.1 (preview)
✅ Phase 1 + Phase 2 in #3307: vocabulary registry, scenes, zip asset type, 11 canonical format definitions, product-format-declaration.json, inputs on format declarations, creative.supported_formats on get_adcp_capabilities, validate_input primitive, preview_creative updates, asset_group_id on format slots (v1↔v2 bridge), SDK codegen scaffolding, URI/canonical/digest-pinned format_id, brand_kit_override. v1 fully supported. list_creative_formats deprecated.
Third-party format authoring guide finalized. Soft warnings on non-canonical slots. v1 product format references soft-deprecated. Server-side flatten wrappers documented.
4.0
v2 product format declarations are the recommended path. v1 still supported with flatten wrappers. Canonical vocabulary becomes MUST for spec-defined formats.
sponsored_placement cluster work blocked on TemplateCreative + OpenRTB Native 1.2 pre-audit (separate issue to be filed).
Walled-garden migration gated on AAO providing a translator from existing format docs to v2 declarations.
Vocabulary governance
Asset_group_id and canonical pattern extensions go through PR + rationale + ≥1 reference adopter, AAO maintainer review, versioned files with content digests.
Soft-warn semantics: validators MAY emit soft warnings on non-canonical asset_group_id values. Warnings are CLI/SDK lint output, NOT protocol-level diagnostics returned in warnings[] fields. Sellers MUST NOT thread soft warnings into protocol responses.
Surfaced by AdCP @adcp/client v6.0 SDK be-Emma test (AudioStack adapter) producing #3268, #3269, #3270 in one round. Audits of 12 social/retail platform adapters (86 formats) and prebid salesagent (GAM tag handling). Three independent specialist reviews (synthesis) plus collaborative working-example walkthrough informed the architecture.
RFC: Creative Formats v2 — canonical formats with tracking baked in, product-bound variants,
validate_inputType: RFC / major additive feature
Severity: high (sets the direction for creative format authoring across 3.x)
Target: 3.1 preview track; stabilize through 3.2/3.3; v1 named-format model deprecation continues into 4.x with full removal at 5.0
Supersedes: #3269 (canonical asset_id slot vocabulary), #3270 (output-validation handshake)
Adjacent: #3268 (PreviewCreativeResponse single-render hoist) — separate but coordinated, ships 3.1
First implementation: #3307 (Phase 1 + Phase 2 preview branch)
Problem
Today's creative format model has friction adopters hit on day one, plus an architectural drift that produced most of that friction:
No explicit "format master" role. Formats are entities in a registry separate from products. Sellers maintain platform-specific format names (
meta_reels,tiktok_in_feed_video,spotify_audio_standard) that are really product-variant declarations. The split forces sellers to author and maintain duplicate metadata and obscures what's universal vs platform-specific.Format
asset_idslots are author-invented strings. Every adopter picksscriptorbodyortextfor "the spoken script body of an audio ad." Asset-group canonical vocabulary exists for catalogs but isn't reused at the format slot level.format_idis a compound{ agent_url, id }object where the name promises a string. Can't be used as a map key. SDK codegen exposes object lookups instead of typed accessors. No content-digest pinning means third-party agents can mutate format definitions mid-flight.No protocol-level handshake for input validation. Creative-template platforms whose output isn't deterministically format-compliant from inputs alone have no clean rejection path.
PreviewCreativeResponserequires four levels of nesting for the single-render case (Simplify PreviewCreativeResponse for the single-render case #3268).Generative formats proliferate. Every social/search/UA platform has 3-7
*_generated_*formats today. Most are structurallycreative_brief+<reference shape>.promoted_offeringsformats duplicated across 8 of 12 platforms with identical internal creative shape.Pure-catalog and AI-surface formats (Amazon SP, Pinterest Collection, Google PMax, ChatGPT-style brand mentions) have no buyer creative slots — they're surface-composed. Modeling as formats with empty creative shapes is awkward; lumping them into one cluster also wrong.
Six different field names for "destination URL" today:
click_url,link,final_url,link_url,landing_page_url,click_through_url.Tracking is mistakenly treated as cross-cutting platform metadata. It's actually format-specific: VAST tracking is the VAST spec; HTML5 tracking is MRAID + OM-SDK; image tracking is impression pixel + click URL. These don't vary platform to platform — they vary format to format. Lumping
image | html | javascriptunder one canonical hides this; treating tracking as a platform-level extension creates needless indirection.Empirical input
Three audits drove this RFC:
vast,daast,html5,iframe,display_tag. Walled-garden hosted assets only.ThirdPartyCreative,CustomCreative,ImageRedirectCreative/VideoRedirectCreative,TemplateCreative(native). Wire format already accepts AdCPdelivery_type: url|inline.Adopter signal: AudioStack
@adcp/clientv6.0 be-Emma test surfaced #3268, #3269, #3270 in a single round.Goals
ProductFormatDeclarationcarrying parameters and platform extensions; they don't replace it.asset_group_id).format_idis a string; canonical formats have short canonical names. URI form (creative-agent capabilities and third-party formats) is content-digest-pinned.validate_input), with explicit handling for nondeterministic generative platforms.build_creativecapabilities targeting canonical formats. Inputs are a typed vocabulary.get_products.brand.json, withbrand_kit_overridefor the missing/stale case.Non-goals
output_modalitydeclaration (deferred until text/audio AI-surface formats need it).Schema strategy
v2 ships side-by-side with v1 in the existing v3 namespace.
v1-compatible primitives shared with v2: asset primitives (image-asset, video-asset, audio-asset, vast-asset, daast-asset), catalog/offering schemas, manifest envelope (
creative-manifest.json), response envelopes.Modified backwards-compatibly:
html-asset.jsonandjavascript-asset.jsonadd optionaldelivery_type: "url" | "inline"(✅ #3307).product.jsonadds optionalformatfield carrying v2ProductFormatDeclaration.Net-new v2 schemas: canonical format definitions (11) +
_base.jsonwith shared parameters includinginputs,product-format-declaration.json,asset-group-vocabulary.json(✅),scenes.json(✅),zip-asset.json(✅),platform-extension-ref.json,validate-input-{request,response,result}.json. Note:build-capability.json,build-capability-ref.json,list-build-capabilities-*.jsonfrom earlier revisions were dropped in r4 — input contract folds into the format declaration; creative-agent capability discovery folds intocreative.supported_formatsonget_adcp_capabilities. Canonical-pattern schemas for cta_vocabulary / destination_kinds / brand_safety / universal_macros were dropped earlier (vocabularies stay where they already live; tracking is baked into formats).Version discrimination: A given product is either v1 (references a separately-defined format by
format_id) or v2 (carries itsformatdeclaration inline). Sellers can publish both during transition.Design
1. Architectural framing — three layers
Canonical formats (11) — AdCP-defined universal building blocks. The canonical format itself is the buyer's contract. Same as OpenRTB and VAST treat creative format: a stable reference buyers validate against before knowing which seller wins. Each canonical bakes in its tracking events, macro substitutions, click handling, measurement integrations — because tracking is format-specific, not platform-specific.
Canonical patterns — cross-format shared concerns published by AAO, compiled into SDKs. Smaller set than I originally drafted:
cta_vocabulary,destination_kinds,brand_safety_frameworks,universal_macros. Tracking is not a canonical pattern — it lives in the canonical format that owns it.Platform extensions — narrow, truly platform-specific additions. Pixel ID formats (Meta vs TikTok vs Google), conversion event taxonomies, platform-specific CTA additions (Meta
WATCH_MORE), platform-specific destinations (Metamessenger_thread,whatsapp_phone). Distributed via URI+digest, bundled inget_productsresponses (see §5c).2. The 11 canonical formats
Split by tracking/measurement model (because tracking is fundamentally different per format) plus output shape.
imagehtml5display_tagimage_carouselvideo_hostedvideo_vastaudio_hostedaudio_daastsponsored_placementresponsive_creativeagent_placementsi_chat(brand-owned conversation; user → brand's agent — different protocol layer). Parallelssponsored_placementstructurally; both surface-composed, differ by surface type.Each canonical format's schema declares:
asset_group_idregistry (or format-specific where role doesn't generalize)universal_macros)destination_kinds)composition_model: deterministic | algorithmic— explicit field;sponsored_placementis deterministic,responsive_creativeandagent_placementare algorithmicprovenance_required?: boolean— optional flag for brand-safety-sensitive products to refuse unsigned synthesized assets (C2PA hooks)Sponsored placement and the SI architectural decomposition
The three sponsored canonicals (
sponsored_placement,responsive_creative,agent_placement) cover part 1 of three architecturally distinct patterns currently conflated under "Sponsored Intelligence":v2 ships #1 inside the canonical format catalog. The other two stay on their respective tracks.
3. Product format declarations — keyed by canonical name
A v2 product carries its format declaration inline, keyed by canonical format name:
The format key (
image,video_vast,audio_hosted, etc.) IS the format declaration. SDKs codegenCanonicalFormats.image({...})accessors matching exactly. Nocanonicaldiscriminator field needed — the key is the discriminator.A product can carry exactly one format key; validators enforce this.
Worked example — Meta Reels (
video_hostednarrowed){ "product_id": "meta_reels_us", "format": { "video_hosted": { "orientation": "vertical", "duration_ms_range": [3000, 90000], "aspect_ratio": "9:16", "min_width": 1080, "min_height": 1920, "max_file_size_mb": 200, "video_codecs": ["h264"], "audio_codecs": ["aac"], "headline_max_chars": 25, "primary_text_max_chars": 72, "captions": "recommended", "cta": { "canonical_set": "cta_vocabulary", "values": ["LEARN_MORE", "SHOP_NOW", "DOWNLOAD", "SIGN_UP"], "extensions": ["meta_cta_watch_more"] }, "destinations": { "canonical_set": "destination_kinds", "values": ["web", "app_install", "deep_link"], "extensions": ["meta_destinations_messenger", "meta_destinations_whatsapp"] }, "brand_safety": "iab_content_taxonomy_3", "platform_extensions": [ { "uri": "https://meta.adcp/extensions/meta_pixel", "digest": "sha256:..." }, { "uri": "https://meta.adcp/extensions/meta_placements_reels", "digest": "sha256:..." } ] } } }The
video_hostedcanonical format already declares OM-SDK measurement, external impression/click/quartile trackers, and macro substitution patterns ({CACHEBUSTER},{CLICK_URL},{OFFERING_ID}etc. fromuniversal_macros). Meta's product narrows duration, dimensions, slot character limits, and references its specific extensions for pixel ID and Reels placement. The buyer sees "video_hosted with these constraints + Meta's extensions" rather than a sea of separately-declared concerns.Worked example — IAB MREC (
imagenarrowed, multi-seller standard){ "product_id": "nytimes_homepage_mrec", "format": { "image": { "width": 300, "height": 250, "max_file_size_kb": 200, "image_formats": ["jpg", "png", "gif"], "ssl_required": true, "cta": { "canonical_set": "cta_vocabulary", "values": ["LEARN_MORE", "SHOP_NOW", "GET_OFFER"] }, "destinations": { "canonical_set": "destination_kinds", "values": ["web"] }, "brand_safety": "iab_content_taxonomy_3", "platform_extensions": [ { "uri": "https://nytimes.adcp/extensions/nytimes_om_strict", "digest": "sha256:..." } ] } } }The
imagecanonical format already declares impression pixel + click URL + optional viewability pixel; NYTimes's product narrows the dimensions to MREC, file size, image formats, and references its strict OM extension. Buyers can validate a manifest against canonicalimageBEFORE knowing which publisher wins — every IAB MREC product across publishers narrows the same canonical with similar parameters. That's the canonical-as-contract value.For HTML5 banners on the same placement, the seller publishes a separate product:
{ "product_id": "nytimes_homepage_html5", "format": { "html5": { "width": 300, "height": 250, "max_initial_load_kb": 200, "max_polite_load_kb": 500, "host_initiated_subload": true, "max_animation_duration_ms": 30000, "max_cpu_load": 30, "mraid_required": true, "om_sdk_required": true, "clicktag_macro": "clickTag", "backup_image_required": true, "backup_image_max_size_kb": 50 } } }The
html5canonical format declares MRAID + OM-SDK + click-tag macro + backup image as part of its tracking spec. NYTimes narrows the dimensions, file size limits, and animation constraints. Different format fromimagebecause the tracking model is fundamentally different.Worked example — Podcast 30s host-read (
audio_hostedwith inlineinputs)Host-reads are the host-recorded-from-buyer-script pattern. The buyer doesn't ship audio — they supply a script and the publisher's host records the audio. The format declaration carries the input contract directly; no separate capability lookup needed.
{ "product_id": "the_daily_30s_host_read_us", "format": { "audio_hosted": { "duration_ms_exact": 30000, "audio_codecs": ["mp3", "aac"], "audio_sample_rates": [44100, 48000], "audio_channels": ["stereo"], "loudness_lufs": -16, "buyer_audio_acceptance": "rejected", "audio_source": "publisher_host_recorded", "tracking": { "extensions": ["podcast_dynamic_insertion_macros"] }, "inputs": { "script": { "required": true, "max_chars": 800, "description": "Verbatim script the host will read. Exact wording — no improvisation; legal pre-cleared." }, "brand": { "required": true }, "offering_ref": { "required": false } }, "production_window_business_days": 7 } } }Two flows depending on whether the buyer pre-produces or the seller produces internally:
build_creative({ format: <The Daily's audio_hosted narrowing>, inputs: { script, brand } })on a creative agent (could be The Daily's own creative-agent surface, the buyer's in-house studio, AudioStack-style services — any agent that lists this format undercreative.supported_formatsonget_adcp_capabilities) → receives rendered manifest → submits viasync_creativesto The Daily's sales agent.sync_creativeswith the inputs directly → seller produces internally (host records, calls upstream creative agent, whatever) → returns async status; buyer polls or waits for completion.The format's
audio_sourceandbuyer_audio_acceptanceparameters tell the buyer which flows are accepted. Both flows are valid for The Daily's host-read because the publisher's host MUST be the producer in either case — the difference is whether the buyer drives the build call or the seller drives it. Other products might accept Flow 1 only or Flow 2 only.Verbatim host-reads use
script; talking-points host-reads usecreative_brief. Same target format; different input contract. The format itself encodes which is needed.Sales agents do not expose
build_creativebuild_creativeis a creative-agent surface only. Sales agents exposeget_productsandsync_creatives. Creative agents may also exposesync_creativesfor the ad server use case (an agent can act as both a creative agent for build flows and an ad server for delivery). Both roles providepreview_creative. Thecreative.supported_formatsfield onget_adcp_capabilitiesis what creative agents declare; it uses the sameProductFormatDeclarationshape as products' inlineformat.4.
format_idas URI string with content-digest pinningv2
format_idis a string. Three valid forms:format_id: "video_hosted"— bare token, resolves to AAO canonical.product_idis the seller-side identity; the product'sformatdeclaration is the source of truth for that variant.format_id: "https://creative.audiostack.com/adcp#audio_30s". Pinned via content digest.Content-digest pinning (required for URI form): Buyers SHOULD include
format_digest: "sha256:...". Agents MUST publish digests. Mid-flight format-definition mutation breaks the digest match; buyers detect drift before validating against a stale shape. Same model as TMP schema-pinning; addresses #2335.For canonical AAO formats, SDKs ship the catalog with versioned digests at well-known paths.
5. Canonical
asset_group_idvocabulary (✅ shipped in #3307)Format slot names draw from a governed vocabulary. ✅ Shipped: 7 catalog vocab entries + 12 audit-driven additions in
static/schemas/source/core/asset-group-vocabulary.json. Includeslanding_page_urlcanonicalizing 6 v1 alias names.Build-time inputs vocabulary for
build_creative:creative_briefscriptscenesvoice_idstyle_referencestarter_assetsproduct_feedScenesschema (✅ shipped at/schemas/v3/creative/scenes.json).5b. Canonical patterns (smaller layer)
Cross-format shared concerns. AAO-published, SDK-compiled. Each is a versioned JSON file with content digest.
cta_vocabularyLEARN_MORE,SHOP_NOW,DOWNLOAD,SIGN_UP,GET_OFFER,BOOK_NOW,CONTACT_US,APPLY_NOW,WATCH_VIDEO)destination_kindsweb,app_install,deep_link,dial_phone,sms)brand_safety_frameworksuniversal_macros{CACHEBUSTER},{CLICK_URL},{OFFERING_ID},{MEDIA_BUY_ID},{CREATIVE_ID}etc.Tracking is not a canonical pattern. Each canonical format declares its own tracking events; they reference
universal_macrosfor substitution. That's the only cross-format tracking concept.5c. Platform extensions — distribution and discovery
Platform extensions are narrow, truly platform-specific additions to canonical patterns or canonical format slots. Examples:
meta_pixel— extendstrackingslots on most formats: addspixel_id,conversion_eventenummeta_destinations_messenger— extendsdestination_kinds: addsmessenger_thread_idmeta_cta_watch_more— extendscta_vocabulary: addsWATCH_MOREfor Reelstiktok_pixel— extendstracking: adds TikTok-specific pixel field shapenytimes_om_strict— extendstracking: adds NYTimes' strict OM-SDK requirementsWhere they live: at well-known paths on the owning agent.
Each extension's response carries: extension schema (which fields it adds), the canonical pattern or slot it extends, version, and content digest.
How buyers get them: bundled in
get_products. The sales agent's response includes definitions for any extension referenced by any product in the response:{ "products": [ { "product_id": "meta_reels_us", "format": { "video_hosted": { ... "platform_extensions": [ { "uri": "https://meta.adcp/extensions/meta_pixel", "digest": "sha256:a3f5..." } ] } } } ], "extensions": { "https://meta.adcp/extensions/meta_pixel@sha256:a3f5...": { "extends": "tracking", "fields": { "pixel_id": { "type": "string", "required": true }, "conversion_event": { "type": "string", "enum": ["PURCHASE", "LEAD", ...] } }, "version": "2.1.0" } } }Buyer's SDK caches by URI@digest. Subsequent
get_productsresponses reference by digest; if buyer already has the extension cached, the inline definition is omitted.Direct URI fetch fallback (
GET https://meta.adcp/extensions/meta_pixel) is supported for tooling/debugging but the primary path is bundled-in-get_products.Why this works:
meta_pixel; buyer fetches once)6. Brand context via
brand.jsonwith explicit overrideWhen a manifest carries
brand: { domain: "acme.com" }, the seller pulls brand context frombrand.json. Override path for missing/stale brand.json:brand_kit_overridetakes precedence overbrand.jsonfor supplied fields.7.
validate_inputprimitive — including nondeterministic generativeBuyer dry-run, format-discovery filter, catalog suitability check;
build_creativecalls internally.Deterministic platforms: validate predictively, reject the input.
predictedcarries the platform's estimate.Nondeterministic platforms (Veo, Sora, Runway-class): predictive validation is a category error. Two protocol obligations:
task_failedwith structuredsynthesis_failedreason carrying constraints unmet, attempts, suggested adjustments.8.
preview_creativeupdatesSingle tool, response shape adapts.
#3268single-render hoist applies for direct mode; nestedpreviews[]for multi-render. New optionalpreview_subset_ids?: string[].9.
build_creative— generative as capability with typed inputsBuildCreativeInputsis a typed map (see §5 vocabulary). Different generative shapes use different combinations. Callsvalidate_inputinternally on produced manifest.10. SDK codegen + canonical catalog distribution
Compiled into SDKs:
cta_vocabulary,destination_kinds,brand_safety_frameworks,universal_macros)Runtime-fetched (cached by URI@digest):
get_productsresponses)format_id)creative.supported_formatsfield onget_adcp_capabilities)Generated bindings per language:
Type-safe parameterization, IDE autocomplete on canonical asset_group_id slot names, version-pinned canonical catalog (digest mismatch detectable), local validation without network.
Codegen scaffolding ships in 3.1 (preview); stable for TypeScript and Python in 3.2.
11. Discovery surfaces by agent role;
list_creative_formatsdeprecated and back-compat-wrappedget_productsis the v2 discovery surface for product-bound formats. Bundles platform extensions inline.creative.supported_formatsonget_adcp_capabilities. Each entry uses the sameProductFormatDeclarationshape as products' inlineformat— keyed by canonical name with parameters andinputs. Creative agents may also exposesync_creativesfor ad-server use cases.Deprecation timeline (revised): v1
list_creative_formatsdeprecated in 3.x but functional through 4.0; sellers SHOULD provide server-side flatten wrappers that derive v1 shape from v2 product format declarations. Removed at 5.0.12. Schema additions and drive-by fixes
✅ Phase 1 (#3307) shipped:
zipasset type atstatic/schemas/source/core/assets/zip-asset.json(replaces the earlier delivery_type addition on html/javascript)asset-group-vocabulary.json,scenes.jsonPhase 2 (this RFC, ✅ in #3307):
schemas/v3/formats/canonical/{image,html5,display_tag,image_carousel,video_hosted,video_vast,audio_hosted,audio_daast,sponsored_placement,responsive_creative,agent_placement}.jsonplus_base.jsonwith shared parameter fields includinginputsandproduction_window_business_daysschemas/v3/core/product-format-declaration.json— keyed-by-canonical-name structureschemas/v3/core/platform-extension-ref.json— URI + content-digest referenceschemas/v3/creative/scenes.json— typed scene-by-scene structure for build_creative inputschemas/v3/creative/validate-input-{request,response,result}.json— buyer dry-run primitivecreative.supported_formatsfield added toget_adcp_capabilitiesresponse (creative-agent discovery)format.jsonslot declarations (Individual* and Group*) gain optionalasset_group_idfield for v1↔v2 migration bridgeproduct.jsonadds optionalformatfield;creative-manifest.jsonadds optionalbrandandbrand_kit_overrideWhat dissolves
composition: 'slot_fill' | 'surface_composed'— derivable from canonical declaration.expansion: 'per_offering' | 'per_item'— derivable fromfield_bindingsshape.output_modality— derivable from canonical's output asset_type.promoted_offeringscampaign mode — collapses into product format declarations + field_bindings.build_creativecapability with typed inputs.brand_kit_override.list_creative_formatsas a single tool — split by agent role.canonicaldiscriminator field — replaced by format-keyed-by-name.iab_sizeredundant labeling — derive from dimensions.image/video/audio— split by tracking model into separate canonicals.build_capabilityandbuild_capability_refas separate concepts (r4) — collapsed intoinputsdirectly on the format declaration. External creative agents are invisible to the buyer; supply-chain relationships stay off the protocol surface.creative_build_capabilitiesfield name (r4) — renamed tocreative.supported_formats; sameProductFormatDeclarationshape as products' inlineformat. One primitive, two homes.build_creativeexposure (r4) —build_creativeis a creative-agent surface only. Sales agents exposeget_productsandsync_creatives; creative agents may also exposesync_creativesfor ad-server use cases.delivery_typeas a discriminator onhtml-asset.json/javascript-asset.json(Phase 1 scrub) — URL-delivered HTML/JS routes throughurl-asset.jsonwith appropriateurl_type; HTML5 zip bundles get a proper first-classzipasset type.What does not dissolve:
Migration
Realistic adoption by adopter type:
creative.supported_formatsmatches what they want to declare.scenes,zipasset type, 11 canonical format definitions,product-format-declaration.json,inputson format declarations,creative.supported_formatsonget_adcp_capabilities,validate_inputprimitive,preview_creativeupdates,asset_group_idon format slots (v1↔v2 bridge), SDK codegen scaffolding, URI/canonical/digest-pinnedformat_id,brand_kit_override. v1 fully supported.list_creative_formatsdeprecated.list_creative_formatsremoved. v1 named-format references removed. v2-only path.Phase gating
sponsored_placementcluster work blocked on TemplateCreative + OpenRTB Native 1.2 pre-audit (separate issue to be filed).Vocabulary governance
Asset_group_id and canonical pattern extensions go through PR + rationale + ≥1 reference adopter, AAO maintainer review, versioned files with content digests.
Soft-warn semantics: validators MAY emit soft warnings on non-canonical
asset_group_idvalues. Warnings are CLI/SDK lint output, NOT protocol-level diagnostics returned inwarnings[]fields. Sellers MUST NOT thread soft warnings into protocol responses.Forward notes (not in v2 scope)
output_modalitydeclaration deferred until text/audio AI-surface formats need it.video_hostedandvideo_vastvia VAST extension. Canonical accepts both.build_creativeoutputs include provenance manifests attributing synthesis to creative agent. Canonical formats withprovenance_required: truereject unsigned synthesized assets.Prior art and references
asset_group_vocabularyBidExt.vast.vpaid— VPAID viavpaid_enabled: trueflagPreviewCreativeResponsesingle-render hoist; pairs withscenes.jsonaudio_daastcanonicalFiles affected
✅ Phase 1 (#3307) shipped:
static/schemas/source/core/asset-group-vocabulary.jsonstatic/schemas/source/creative/scenes.jsonhtml-asset.json,javascript-asset.json(delivery_type)docs/creative/channels/video.mdx,audio.mdxfixesPhase 2-3 (this RFC):
schemas/v3/creative/canonical-formats.json(index)schemas/v3/formats/canonical/{image,html5,display_tag,image_carousel,video_hosted,video_vast,audio_hosted,audio_daast,sponsored_placement,responsive_creative,agent_placement}.jsonschemas/v3/creative/product-format-declaration.json,validate-input-{request,response,result}.jsonschemas/v3/patterns/{cta-vocabulary,destination-kinds,brand-safety-frameworks,universal-macros}.jsonproduct.json(addformat);creative-manifest.json(addbrandandbrand_kit_override);format.jsonslot declarations gain optionalasset_group_id(v1↔v2 bridge);get_adcp_capabilitiesresponse gainscreative.supported_formatsTools:
Source
Surfaced by AdCP
@adcp/clientv6.0 SDK be-Emma test (AudioStack adapter) producing #3268, #3269, #3270 in one round. Audits of 12 social/retail platform adapters (86 formats) and prebid salesagent (GAM tag handling). Three independent specialist reviews (synthesis) plus collaborative working-example walkthrough informed the architecture.