Skip to main content
A product describes inventory along three independent axes:
  • Publisher properties — WHERE the ad runs (youtube.com, spotify.com)
  • Collections / installments — WHAT CONTENT the ad runs in or around (a specific series and its installments)
  • Placements — WHAT POSITION the ad appears in (pre-roll, mid-roll, host read)
Collections and placements are parallel dimensions, not hierarchical. “Pre-roll” is a position. “Pinnacle Challenge” is content. A product combines them: “pre-roll on Pinnacle Challenge on Acme Streaming.”

Channel mapping

The collection/installment model maps to familiar concepts across media channels: The kind field on each collection indicates how to interpret it and its installments.

The collection object

A collection is a persistent, publisher-controlled content program that produces installments over time. It is not a social “collection ad,” user conversation, session, prompt, turn, or inferred topic cluster. Collections work like properties — publishers declare them in their adagents.json, and products reference them via collections selectors with publisher_domain and collection_ids.

Collection cards (experimental)

images, sample_content, url and talent[].brand_ref give a creator or show a card: a picture, samples of its content, a page to link out to, and a typed link to the person’s brand identity. Sellers that populate them list media_buy.collection_cards in experimental_features. Publishers declaring collections in adagents.json (and registry collection.* events, which embed the same object) cannot list experimental features, so consumers treat these fields as experimental wherever they appear. Collection cards reach buyers in-band. Products keep their {publisher_domain, collection_ids} selectors, and when the buyer sets include_collections: true the get_products, list_products, request_proposals and refine_proposals responses can carry a top-level collections array with the full object for each referenced collection (see collections in responses). Sellers that list media_buy.collection_catalog also serve the same cards outside a brief through list_collections, by key or with filters, and push card changes to buyer mirrors through collection card webhooks. For a creator marketplace or a large podcast network this replaces fetching every publisher’s adagents.json to draw one proposal, and it keeps fast-moving facts such as samples current. Sellers can also attach samples to the product card with the sample_content reference asset role, as a url asset built from post_url (the role cannot carry platform, published_at or identity_ref). Consumers skip sample_content entries without post_url, and reference_authorization and identity_ref are not authorization to reuse a sample. brand_ref and brand_url identify the same brand when brand_url’s host equals brand_ref.domain; only domain and brand_id are read on talent. Each fact has one home: The collection does not copy person-level identity. A buyer that wants the person resolves brand_ref to a brand agent and calls get_brand_identity, which returns the person’s logos (their picture, always public), description and, with fields: ["collections"], the person’s other channels as {publisher_domain, collection_id} links (experimental, brand.collection_links). A brand_ref is the publisher’s claim about who appears; buyers SHOULD treat it as confirmed only when that person’s get_brand_identity collections lists the same {publisher_domain, collection_id} back. Showing the person’s picture from logos on a card is not a likeness license: using a likeness in an ad goes through the rights lifecycle. To browse a seller’s cards outside a brief, or to look one up by key, use list_collections (experimental, media_buy.collection_catalog). Keep arrays short: adagents.json has fetch-size budgets, so images and sample_content are capped at 10 entries each. sample_content carries no kind; the platform URL implies it. images, sample_content and url are excluded from the publisher_collection definition pin projection, so refreshing a thumbnail or a sample does not fail committed proposals with REFERENCE_DEFINITION_CHANGED.

Programmed channels and owner-sold carriage

FAST describes a channel’s carriage and monetization model, not a distinct kind of inventory. AdCP represents the underlying programmed audio or video stream as a channel collection. The same structure applies to FAST, virtual linear, and syndicated audio channels. This preserves three independent inventory axes:
  • the host CTV app is the property where the ad runs;
  • the programmed channel is the collection whose content surrounds the ad;
  • pre-roll, mid-roll, or another avail is the placement within the product.
The channel owner declares the canonical collection in its own adagents.json. Each distribution entry can name both the host properties carrying the channel and identifiers used by the host or an independent metadata system:
platform_channel_id is the generic fallback for a host-assigned channel identifier. Its namespace is the enclosing publisher_domain; the stable identity is therefore (publisher_domain, value). Because the tuple is what identifies the channel, this type is only meaningful inside a distribution entry: it MUST NOT appear in bare {type, value} identifier lists (distribution_ids sources, exclude_distribution_ids filters), where a value like 1005 would silently collide across hosts. Use the platform’s stable catalog identifier, not an EPG position number — hosts renumber lineups. Use a more specific identifier type when one exists. A distribution entry carries property_ids, identifiers, or both. Distributions SHOULD include identifiers whenever the host assigns one, and consumers MUST NOT assume identifiers is present — a property-only entry is valid, and is the shape an owner ships when the host has not yet published identifiers to cite. The owner’s distribution declaration is a discoverability claim, not sales authorization. For verified owner-sold carriage, the host’s adagents.json authorizes the owner’s sales agent for the host property and narrows that grant to the owner’s canonical collection:
The seller’s product then combines the same host property and owner collection. The placement may be seller_inline, so the host does not have to enumerate the channel owner’s avail definitions:
Buyers MUST NOT treat a seller as authorized for owner-sold carriage absent a host authorized_agents entry matching the host property scope and the owner’s collection selector. Missing host authorization fails closed. Dangling references fail closed the same way: a distribution[].property_ids value that does not resolve to a property in the host’s adagents.json MUST be treated as unverified carriage. A host that carries many of one owner’s channels does not need to track the owner’s collection IDs. A collection selector without collection_ids is a bulk grant: it scopes the authorization to every collection declared in that publisher’s adagents.json. This matches how carriage deals are structured — the host’s contract is with the owner, not with each channel — and avoids a cross-company ID-sync dependency that would silently break the supply path when the owner renames a collection:
Position-specific host narrowing has a namespace rule. Host placement_ids and placement_tags resolve against placements published in the host’s own adagents.json; they never match a seller’s seller_inline placements, which live in the owner’s namespace. A host that must constrain positions therefore publishes those placement definitions itself, and owner products MUST reference them via kind: "publisher_ref" into the host namespace. seller_inline placements and host placement narrowing are mutually exclusive on the same supply path — owner-sold carriage without position constraints is the shape that keeps hosts out of the owner’s avail definitions.

Verification states

The host attestation will roll out unevenly — channel owners have a direct incentive to publish; hosts publish on their own schedule. Buyer agents SHOULD distinguish three states rather than inventing their own interim policy:
  1. Verified owner-sold. The host’s adagents.json authorizes the seller for the host property, narrowed by the owner’s collection selector (exact or bulk grant). Full supply-path verification; suitable for enforcement.
  2. Host-delegated. The host has not published a collection-narrowed adagents.json entry, but its app-ads.txt (or ads.txt) names the owner via inventorypartnerdomain=, and the owner’s own adagents.json names the sales agent and the channel collection. The inventorypartnerdomain line is host-authored, so it is genuine host-side evidence that the owner sells some of this property’s inventory — but it binds neither the agent URL nor the collection, so it MUST NOT be treated as equivalent to the collection-narrowed entry. Buyers MAY accept this state under their own policy, the way DSPs ran ads.txt grace periods.
  3. Owner-attested. Only the owner’s distribution[] entry asserts carriage. This is discovery data with no host-side corroboration; buyers MUST NOT treat it as sales authorization.
For hosts, the collection-narrowed entry is not a new favor to a competitor’s sales path: it is the machine-readable form of the carriage contract’s existing owner-sales clause, and the upgrade path from an inventorypartnerdomain line they typically already publish.

Canonical verification semantics

The registry supply-path endpoint returns semantics_version: "1". Its evaluator and authoritative SDK implementations consume the same canonical golden vectors. Consumers MUST NOT treat results from older evaluator semantics as equivalent to version 1. Version 1 requires an affirmative host collections selector naming the owner. A broad property grant with no collection constraint does not attest owner-sold carriage. Every claimed host property ID must resolve, and the matching grant must cover all of them. Identifier-only distribution entries remain valid discovery data, but cannot prove a host property binding. Missing or unknown authorization discriminators and their companion selectors fail closed on both the owner’s and host’s agent declarations. Malformed selectors and country, effective-time or placement constraints that cannot be evaluated in the supplied context also fail closed. Revocations take precedence over declarations. Agent URL identity follows the protocol canonicalization rules and preserves case-sensitive paths and query values. A query omitting collection_id returns the strongest complete individual collection path. It never combines one collection’s carriage with another collection’s authorization. The weaker host_delegated state retains its documented owner declarations plus host inventory-partner evidence requirements; it does not require a host adagents.json, prove concrete property coverage, or override revocation. Two verified paths can legitimately overlap. In a revenue-share deal the host’s agent and the owner’s agent may both offer avails on the same property and collection; in an inventory-split deal they sell disjoint avails. Verification implies neither exclusivity nor disjointness — buyers dedup at delivery and measurement, as with any multi-path supply. A host that wants the split machine-readable can tag its retained avails with placement_tags. Multiple parties with sales rights do not require a new concurrency primitive. The host publishes one authorized_agents[] entry per sales path and narrows each entry to the relevant collection. A technology provider does not become a rights-holder merely by operating the path. If it supplies software behind the owner’s endpoint, the path may remain direct; if it operates the sales endpoint on the owner’s behalf, the host names that endpoint and marks the path delegated. Syndication chains with an aggregator in the middle (owner → playout/ad-tech aggregator → host, common for FAST outside the owner’s home market) collapse to the same shape: the host attests each terminal sales path directly. When the aggregator holds the sales rights for its inventory share, the host authorizes the aggregator’s agent — delegated, narrowed to the owner’s collection (the bulk-grant selector fits here, since the host may know the owner only through the aggregator). There is no transitive attestation: a host entry naming the aggregator does not authorize agents the aggregator engages downstream; each selling endpoint the buyer can transact with needs its own host entry. The aggregator, holding both contracts, is the natural broker of the collection selector values. Internal allocation terms such as revenue shares, buyback rights, and backfill priority are not discovery or authorization data. Each seller applies those terms when constructing and pricing its products; buyers see the resulting offer, not how the participating parties divide the proceeds. The registry admits cached manifests for supply-path legs only when their provenance is a direct publisher-origin fetch or a publisher authoritative_location delegation, the observation is no older than seven days, and its cache expiry has not elapsed. Manager and community discovery results need additional publisher authority proofs and are not enforcement evidence. Successful-fetch provenance is stored atomically with the manifest, separately from last-attempt diagnostics; cache rows created before this provenance was recorded must refresh before they can establish authority. Registry sources expose owner_fetched_at, host_fetched_at, and resolved URLs separately from the verdict’s checked_at. Both authoritative verification and the registry retain observed revocations by authority and publisher domain for seven days from first observation; changing revoked_at does not restart that clock. The registry uses the existing persistent SDK document store so workers and restarts share the hold and authoritative-location pin. A changed pin rejects until an operator independently confirms the publisher migration; an operator can run npx tsx server/scripts/approve-supply-path-authority.ts <publisher-domain> <https-location> --confirm-publisher-migration with DATABASE_URL after independently confirming the migration. This calls approveSupplyPathAuthorityChange while preserving revocations. Never run it from an automatic retry. Properties read from a cross-origin shared authoritative document must explicitly attribute their publisher. IAB evidence allows at most three exact-HTTPS-origin redirects, with bounded bytes and time per fetch. Collections in a cross-origin authoritative document must explicitly name their owning publisher_domain, just as shared host properties must identify their publisher. A domain pointing at an unrelated public catalog cannot borrow that catalog’s collections, including through weaker inventory-partner evidence. Publisher-origin collection declarations may omit the field. Owner agent grants in shared cross-origin documents must also explicitly select that owner through collections[].publisher_domain; an absent collections constraint cannot authorize every member. Within that owner namespace, omitted collection_ids still grants all collections.

The installment object

An installment is a specific installment of a collection. Not all installments will be known in advance — a weekly podcast may only have next week’s installment scheduled, and some installments may be tentative (a playoff Game 7 depends on Game 6).

Episode status lifecycle

Expected transitions: scheduled or tentative → live → aired or published. A scheduled installment may become postponed (delayed) or cancelled. A postponed installment returns to scheduled when rescheduled. A tentative installment resolves to scheduled, cancelled, or postponed.

Inheritance from collections

Episodes inherit collection-level fields they do not override:
  • content_rating: Episode value overrides collection baseline. When absent, the collection’s rating applies.
  • special: Episode value overrides collection-level special. When absent, the collection’s special applies. A regular collection can have event-anchored installments (e.g., a daily news collection with an election night special).
  • guest_talent: Additive to the collection’s recurring talent — does not replace it.
  • topics: Additive context for brand safety, not a replacement for the collection’s genre.
Buyer agents evaluate both levels: the collection baseline provides the default safety profile, and installment fields refine it for specific installments.

Installment deadlines

Episodes can carry booking, cancellation, and material submission deadlines. These apply to any channel where inventory is tied to a scheduled unit — print issues, podcast installments, influencer posts, linear TV airings, DOOH rotations. Deadlines MUST be chronologically ordered: booking_deadline ≤ cancellation_deadline ≤ each material_deadlines[n].due_at (ascending by array index) ≤ the installment’s scheduled_at. Buyer agents SHOULD reject installments where deadlines violate this ordering. change_cutoff is the operational lock for changes: broadcast traffic/log close, OOH posting-cycle lock, print issue close, or cinema reel lock. A creative swap, pause, or cancellation instruction received after it may not take effect. It is distinct from cancellation_deadline, which is the penalty-free cancel window: a cancellation after change_cutoff may still be billed even if it falls within terms. It is also distinct from booking_deadline, which governs new bookings. When both are present, change_cutoff SHOULD NOT precede booking_deadline. If change_cutoff is absent, the seller makes no statement about when changes stop taking effect. The ordering above does not constrain change_cutoff relative to cancellation_deadline or material_deadlines. Each material deadline has: The two-stage pattern — draft then final — covers a wide range of channels:

Podcast with deadlines

Influencer post with deadlines

Deadlines are optional. Run-of-collection digital products typically omit them. The pattern is most valuable for guaranteed inventory with advance material requirements.

Deadline policy

High-frequency collections (daily newspapers, weekly podcasts) would generate large payloads if every installment carried explicit deadlines. The deadline_policy on a collection declares lead-time rules that agents use to compute deadlines from each installment’s scheduled_at.

Daily newspaper with policy

Instead of enumerating deadlines for every issue, the collection declares the rule once:
For the April 1 issue (scheduled_at: "2026-04-01"), an agent computes:
  • Booking deadline: 4 business days before = March 26
  • Cancellation deadline: 3 business days before = March 27
  • Material due: 2 business days before = March 28
Episodes with explicit deadlines override the policy. A special edition with tighter turnaround declares its own deadlines; regular issues inherit from the policy.

Weekly podcast with policy

Policy vs explicit deadlines

When both are present, explicit installment deadlines take precedence. An agent SHOULD NOT compute deadlines from the policy for installments that have their own.

Specials and limited series

Collections can carry optional annotations that signal their nature to buyer agents. These are composable — a collection can be both a special and a limited series (e.g., a 4-installment Olympics documentary).

Specials

A special is content anchored to a real-world event or occasion. The special object can appear on both collections and installments. On a collection, it means the entire collection is event-anchored. On an installment, it means that specific installment is event-anchored (and overrides the collection-level special when present, following the same inheritance pattern as content_rating).
The special field is distinct from cadence. Cadence describes release frequency (event = one-time or occasional). The special object describes what real-world event anchors the content and when it happens — information a buyer agent needs to evaluate timing relevance and premium pricing.

Limited series

A limited series is a bounded content run with a defined arc. Unlike ongoing series, limited series have a planned end.
This tells buyer agents that The Ember is a finite opportunity — 8 installments over 7 weeks. The limited_series field is distinct from season: a collection can have seasons without being limited (ongoing series have seasons too), and a limited series is a structural commitment that the collection has a planned end.

How products reference collections

Products reference collections via collections — an array of {publisher_domain, collection_ids} selectors that point to collections declared in the publisher’s adagents.json. This is the same pattern as publisher_properties. Full collection objects come from the response’s top-level collections array when the buyer asks for them with include_collections and the seller includes them, and otherwise from the publisher’s adagents.json. Episodes are listed per-product in the installments array, since different products may scope different installments of the same collection.

Reporting actual delivery

Discovery and delivery answer different questions. A collection’s distribution metadata or a product’s property selectors say where content is carried or sellable. After purchase, get_media_buy_delivery can report by_collection, by_property, and by_installment marginals. Those independent arrays do not prove a relationship between their rows. Products that declare supports_collection_property_breakdown can return by_collection_property, whose rows are affirmative evidence that a collection actually delivered on a specific property. For a scheduled airing, episode, issue, or programming block, supports_installment_property_breakdown enables by_installment_property, proving that the specific installment delivered on the host property. This is the grain needed to distinguish the same programmed airing across two host apps without inferring delivery from catalog carriage. Collections and installments use publisher-scoped references; property rows use a publisher-scoped operational identifier and add a catalog property reference when one exists. If the response is truncated or suppressed, an absent intersection row proves nothing. For an installment’s own lifecycle, by_installment rows can carry an experimental installment_status (including postponed and cancelled) and, for a digital installment that published, a publication record with its published_at and the URL of each post. See Installment lifecycle and proof of publication.

Run-of-collection (no specific installments)

A product can reference a collection without listing installments. This means “inventory across this collection, whatever installments air during the flight dates”:

Specific installments

For premium or guaranteed buys, the seller scopes to specific installments:

get_products response structure

Products reference collections via collections selectors — the same pattern as publisher_properties. Each selector has a publisher_domain and collection_ids array pointing to collections declared in that publisher’s adagents.json. When the request sets include_collections: true, the response can also carry the full collection objects, described below.

Collections in responses

get_products, list_products, request_proposals and refine_proposals responses can carry a top-level collections array (experimental, media_buy.collection_cards). Each entry is a full collection object with publisher_domain required, because collection_id is unique only within its publisher.
  • Opt-in. Each of those requests takes an optional include_collections boolean, default false. Sellers MUST NOT return collections unless the request set include_collections: true, so buyers that only need selectors never pay for the objects. The get_products request accepts unknown fields, so a seller without the feature ignores the flag there. The other three requests reject unknown fields, so buyers send the flag only to sellers that list media_buy.collection_cards in experimental_features.
  • Scope. Entries cover collections referenced by a returned product’s collections selectors, keyed by (publisher_domain, collection_id). Sellers MUST NOT include a collection that no returned product references. On a paginated read, that means products on the current page. The array appears only alongside products, never on a rejected or unchanged response, and a fields projection that omits product collections omits it too.
  • Completeness. When include_collections is true, sellers SHOULD include every referenced collection. Omission is allowed, for example for a very large bundle. Buyers detect omissions by comparing the products’ selectors with the array, and resolve a missing collection from the publisher’s adagents.json, as before.
  • Duplicates and strays. If a key appears more than once, that collection is unresolvable from the response, and buyers fall back to adagents.json for it. Buyers ignore entries that no returned product references.
  • Authority. The response entry is a convenience copy from the selling agent. The publisher’s adagents.json remains the root of authorization: which agent may sell which collection is answered only by its authorized_agents entries, including collection-scoped selectors. A response copy MUST NOT be treated as authorization evidence. When the copy and adagents.json disagree, the copy wins only on images, sample_content, url, description, season, cadence and distribution[].followers. Every other field, including status, talent, content_rating, genre, kind, special and the rest of distribution, stays anchored to adagents.json. A copy that omits one of the closed-list fields leaves the declared value. A copy’s followers apply to the declared distribution entry with the same publisher_domain (or, when several declared entries share it, the one with the same identifiers); copy entries the publisher does not declare are ignored. season and cadence are on the list because they go stale between updates to the publisher’s file and drive neither suitability nor pricing. Facts buyers use for suitability or pricing, such as content_rating, genre and production_quality, stay with the publisher so that a reseller cannot restate them. Definition pins hash the adagents.json declaration, never the response copy.
  • Unverified copies. An entry whose (publisher_domain, collection_id) is not declared in that publisher’s adagents.json, or that comes from a selling agent that adagents.json does not authorize for the collection, is unverified display data. It does not establish that the collection exists or is sellable, and buyers MUST NOT present it as the publisher’s declaration. A response copy’s distribution MUST NOT feed the carriage verification states, which read distribution[] only from the owner’s own file.
  • Feed versions. include_collections is part of the version scope of the get_products wholesale_feed_version and the list_products feed_version, for both public and account cache_scope. Absent and false are the same scope. Without the flag, collection copies are outside the version, so a card change alone never makes a buyer that did not ask for cards refetch the feed. With include_collections: true, the version also changes whenever any collection copy those reads would return changes, so an unchanged response never hides a fresher copy. A token issued under one setting and presented with the other is a mismatch, and the seller returns the full payload, as for any other scope-key difference. Sellers MUST issue distinct tokens for the two settings so the mismatch is detectable. Wholesale feed webhooks for products carry no collections, and their versions belong to the scope without the flag. A webhook-fed mirror keeps cards current through the collection_card.* and collection_catalog.bulk_change events (experimental, media_buy.collection_catalog), which carry their own list_collections version. Against a seller without them, it refreshes cards through a full read with include_collections: true.
Selectors on products are unchanged, so a buyer that ignores collections keeps working.

Canonical collection identity

A collection’s identity is {publisher_domain, collection_id} — scoped to the publisher that declares it in their adagents.json. This means any collection creator can serve as their own canonical registry.

Creator as canonical publisher

A creator like MrBeast declares collections in mrbeast.com/adagents.json. Any seller packaging that creator’s inventory — a YouTube sales house, a CTV distributor, the creator’s own team — references the same canonical source:
The buyer sees mrbeast.com + beast_games regardless of which seller or platform the inventory comes from. No cross-referencing of IMDb IDs or distribution identifiers needed — the creator’s domain is the registry.

When creators don’t publish adagents.json

Not every collection has a creator-owned domain. A streaming platform’s original series may only exist in that platform’s adagents.json. In that case, the platform is the canonical publisher and collections points to their domain. Distribution identifiers on the collection object handle cross-seller matching when the same collection appears on multiple platforms without a single canonical source.

Identity resolution priority

Buyer agents should resolve collection identity in this order:
  1. Canonical publisher — publisher_domain + collection_id from the creator’s own adagents.json. Strongest signal.
  2. Platform-independent identifiers — imdb_id, gracenote_id, eidr_id from the collection’s distribution array. Reliable cross-reference when no canonical publisher exists.
  3. Platform-specific identifiers — Spotify, Apple, YouTube IDs. Useful within a platform but not universal.

Discovery examples

CTV collection with installments

A streaming platform selling sponsorships against a known collection with upcoming installments:
A streaming platform offering a main collection and its companion after-collection, plus highlight clips:
The highlight clip references its source installment via derivative_of. The companion after-collection is linked via related_collections on the main collection — buyers targeting Nova Kitchen can discover the after-collection as an additional reach opportunity.

Podcast with distribution

A podcast network selling across multiple distribution platforms. The collection’s distribution array in adagents.json captures the full distribution footprint; buyers use distribution identifiers for cross-seller matching:
Tentative installments (ep48, ep49) have no names or guest info — they have not been produced yet. The buyer evaluates based on the collection’s baseline profile and the known details of ep47.

Live event with tentative installments

A sports league selling sponsorships against a live event series. Live broadcasts use flexible_end because game duration is unpredictable, and unplanned_breaks because ad breaks follow game flow (timeouts, period breaks) rather than a fixed schedule. The tentative Game 5 depends on the series outcome — it only happens if neither team wins in four games.
This pattern combines several features designed for live inventory: cadence: "event" signals a non-recurring series, flexible_end tells buyers the broadcast length is approximate, and unplanned_breaks: true indicates ad breaks follow game flow rather than a predetermined schedule. The tentative Game 5 includes valid_until so buyer agents know when to re-query — if the series ends in four games, that installment will resolve to cancelled. Buyers should always check valid_until on tentative installments before committing budget.

Discovering collections

Buyers discover collections through the standard get_products workflow. Natural language briefs drive collection selection:
The seller returns products with collections selectors and, when the request set include_collections: true, may include the full objects in the response’s top-level collections array. A seller that lists media_buy.collection_catalog also lets buyers browse or look up its cards directly with list_collections. The buyer resolves any others from each publisher’s adagents.json. Registry clients can also bootstrap and look up the crawled collection catalog through /api/registry/catalog/collections/sync and /api/registry/catalog/collections/distribution, which is useful for cross-referencing platform aliases such as YouTube channel IDs back to the publisher-declared collection. For community-maintained entries, registry moderators can seed a publisher-scoped collection with PUT /api/registry/catalog/collections/{publisher_domain}/{collection_id}. This creates a contributed registry record and emits the same collection.created / collection.updated feed events. It does not replace publisher-origin proof: once the publisher declares the collection in their own adagents.json, the authoritative declaration wins.

Brand safety

Collections provide a two-level brand safety model: a collection baseline and per-installment overrides.

Collection baseline

A collection’s default brand safety profile comes from:
  • content_rating — the collection’s declared rating system and value
  • genre — content categories (ideally using genre_taxonomy for machine-readable evaluation)
  • talent — hosts and recurring cast, with optional brand.json references for deeper evaluation
This is what buyers evaluate when individual installment content is not yet known.

Installment overrides

When installment details are available, they can shift the safety profile:
  • A content_rating that differs from the collection baseline (this week is TV-14 instead of TV-PG)
  • guest_talent that changes the talent profile (a controversial guest)
  • topics that add installment-specific content signals

What is not modeled

AdCP does not predict content safety for unknown future installments. A buyer who commits to “all April installments” buys based on the collection’s baseline profile, accepting variation. The seller’s content standards and the collection’s track record are the buyer’s basis for that decision.

Distribution identifiers

Each collection’s distribution array maps it to specific publisher platforms using host property_ids, platform identifiers, or both. Identifiers enable cross-seller matching: when two different sellers both offer products for the same collection, a buyer agent can match them via shared identifiers.

Cross-seller matching

Platform-independent identifiers are the most reliable for deduplication: Collections SHOULD include at least one platform-independent identifier when available.

Platform-specific identifiers

Available podcast types: apple_podcast_id, spotify_collection_id, rss_url, podcast_guid, amazon_music_id, iheart_id, podcast_index_id. Available video/CTV types: youtube_channel_id, youtube_channel_handle, youtube_channel_url, youtube_playlist_id, amazon_title_id, platform_channel_id, roku_channel_id, pluto_channel_id, tubi_id, peacock_id, tiktok_id, twitch_channel. Other: domain, substack_id. For YouTube channels, youtube_channel_id is the preferred canonical identifier; handles and URLs are aliases for discovery and matching when the channel ID is not yet resolved.

Creator and show cards (experimental)

A buyer comparing creators or shows wants a card: how many followers, who watches, how many views a typical installment gets. Each fact has one home, and no collection-level audience_stats object exists. Composition and views are inline on the product. The follower count lives on the collection that the product’s collections selector resolves to. Sellers that list media_buy.collection_cards return full collection objects in the response’s top-level collections array when the request sets include_collections: true (see collections in responses), and sellers that also list media_buy.collection_catalog serve the same objects through list_collections without a brief. A buyer ranking creators reads distribution[].followers there. followers is one of the fields where a verified response copy wins over adagents.json. For other sellers, and for any collection the response omits, the buyer resolves the collection from the publisher’s adagents.json, which takes one fetch per publisher.

Follower counts

distribution[].followers is the platform-reported follower or subscriber count for the collection on that publisher_domain. It reuses audience-size, so it carries a range, a precision, and an as_of:
  • Use precision: "approximate" when the platform rounds publicly, as video platforms do with subscriber counts: a displayed “1.23M” is the interval 1,230,000 to 1,239,999. Use exact only when the platform reports an exact count, in which case lower_bound equals upper_bound.
  • as_of is when the count last changed, not when it was last read. A refresh that leaves lower_bound, upper_bound and precision unchanged is not a change: the seller keeps the earlier as_of, no feed or list_collections version moves, and no collection card webhook fires. A scheduled sweep can therefore check every count without forcing buyers to resync. Buyers comparing two creators compare as_of first.
  • The value counts accounts, not de-duplicated people, even though audience-size is worded for people. A person who follows the same creator on two platforms is counted twice, so buyers MUST NOT sum followers across distribution entries or treat it as reach.
  • Display and comparison only. It is not a targeting predicate and does not size a buyable audience.
  • It is outside the definition pin projection: a refreshed count does not change the collection’s content_digest, while any other change to a distribution entry does.
A seller that serves or relays collection objects carrying followers MUST list media_buy.collection_cards in experimental_features on get_adcp_capabilities. A publisher authoring the field directly in adagents.json has no capabilities response; the field is experimental either way. See experimental status.

Audience composition

Creator audience composition is product-level audience evidence. No new field is needed. A creator’s own analytics are a platform report, so declare them with:
  • evidence_type: "seller_declared". Independent verification is carried by attestation_refs, never inferred from this value.
  • methodology: "observed".
  • provider set to the platform’s brand reference. It names the source of the numbers, not an attester: creator analytics are usually private to the creator and the platform has not verified this snapshot unless an attestation_ref says so.
  • a baseline naming the platform’s viewer population.
This evidence says that 62% of the channel’s viewers are 18 to 24 years old:
As with all audience evidence, this is population-level planning information. It is not a targeting predicate and not proof about any impression. Only the age dimension has a built-in vocabulary today, so a gender split currently needs a provider-defined HTTPS URI with a taxonomy; a canonical gender dimension is proposed but not yet defined. audience_evidence is built for immutable, digest-pinned snapshots, so a marketplace emitting it per creator should limit it to the few dimensions a card needs. Evidence is not delivery reporting. by_demographic in get_media_buy_delivery reports what a buy delivered; it does not carry a creator’s pre-purchase audience.

Average views per installment

Report it as the views metric in the product’s forecast, or in the proposal’s forecast when the seller is answering a brief. The forecast already carries ranges, so a creator whose recent videos vary widely can say so. This is the seller’s projection for the proposed buy, not a trailing average of past videos, and the forecast has no per-installment unit; state the basis in the product description until the WG decides whether a trailing-window metric is needed.

Ad inventory

Episodes declare break-based ad inventory in the ad_inventory object: For non-break ad formats like host reads, custom integrations, or sponsorships, use product placements instead. A podcast product might have a placement for “mid-roll host read (60s)” — that is a placement on the product, not part of ad_inventory.

Relationship to LEAP

The installment model aligns with IAB Tech Lab’s LEAP Forecasting API for live streaming events: LEAP targets SSP-to-DSP plumbing. AdCP operates at the agent-to-agent negotiation layer where buying decisions happen.

Collection targeting

Products with multiple collections default to bundles — the buyer gets all listed collections. Sellers can set collection_targeting_allowed: true to let buyers target a subset, the same pattern as property_targeting_allowed for properties. Selection travels in targeting_overlay.collection_selection, mirroring placement_selection: mode: "selected" names the complete required set as domain-qualified selectors with explicit collection_ids (the domain-only bulk-grant form is authorization scoping, not selection), and mode: "default" accepts the product’s full bundle. Buyers who manage selection through lists keep using collection_list / collection_list_exclude refs.
On package readback, collection_selection is also the audit surface: sellers MUST echo the committed collection selection there as concrete selectors — including the materialized result of any collection_list composition — so a buyer can verify what content programming a package runs against without re-resolving mutable lists or re-fetching the product catalog. A purchase made with mode: "default" therefore reads back as mode: "selected" naming the product’s complete bundle; the default branch carries no selectors and cannot satisfy the echo. For a channel buy this is the readback of the one axis that makes the product distinct: the channel itself.

Multi-collection bundles

A single product can span multiple collections by listing multiple collection IDs in collections. When a product has multiple collections, each installment MUST include canonical collection_ref so the buyer agent knows both the parent collection and its publisher namespace. The deprecated collection_id shorthand is only unambiguous for single-namespace products.
A magazine publisher selling display ads across upcoming issues. Each issue is an installment with deadlines for booking, cancellation, and material delivery:
The collection/installment model works identically for print publications and audio/video content. The installment’s deadlines object replaces what the German OBS system handles through separate message exchanges — booking, cancellation, and material delivery are all visible upfront.

See also

  • Media products — the full product model
  • Print ads — print-specific creative formats, physical dimensions, bleed, and DPI
  • brand.json — talent identity and brand safety evaluation
  • Product discovery — how buyers discover inventory via get_products