Skip to content

RFC: property dimension in get_media_buy_delivery reporting breakdowns (by_property) #5880

Description

@nastassiafulconis

Problem

Buyers optimizing multi-publisher buys need to know where impressions actually delivered, at the level of the property (domain, app, CTV channel), so they can shift budget toward properties that perform. Today get_media_buy_delivery cannot answer "how many impressions ran on cnn.com vs bbc.com" for any buy.

This also breaks the protocol's own governance loop. validate_property_delivery consumes delivery records keyed by property identifiers:

{ "identifier": { "type": "domain", "value": "www.nytimes.com" }, "impressions": 103 }

and the documented feedback loop says step 1 is "pull delivery data via get_media_buy_delivery" - but no AdCP task produces delivery data in that shape. Buyers currently need log-level data or a verification vendor to feed AdCP's own governance validation.

What exists today

  • reporting_dimensions on get_media_buy_delivery already supports request-controlled, capability-gated breakdowns: geo, device_type, device_platform, audience, placement, each with limit, sort_by, and a *_truncated flag.
  • by_placement rows MAY carry publisher_domain (the adagents.json namespace). That gives namespace attribution, but placement granularity is finer than property, and top-N truncation (default 25) means per-domain totals cannot be reconstructed from placement rows on large buys.
  • Discovery recently gained a publisher_domain filter on get_products (feat(training-agent): add publisher_domain filter to get_products #5867). Buyers can now select inventory by publisher namespace but cannot attribute delivery back to it - the loop doesn't close.
  • publisher_properties (required on every product) declares the coverage claim at discovery time. This RFC adds the delivery truth to pair with it.

Proposal

Additive, minor-safe. Follows the existing dimension pattern exactly.

Request - new key in reporting_dimensions:

{
  "reporting_dimensions": {
    "property": { "limit": 50, "sort_by": "spend" }
  }
}

Response - by_property (+ by_property_truncated) within each by_package entry. Each row is delivery-metrics plus identity:

{
  "by_property": [
    {
      "identifier": { "type": "domain", "value": "cnn.com" },
      "publisher_domain": "cnn.com",
      "property_id": "prop_cnn_web",
      "impressions": 450000,
      "spend": 2250.00
    },
    {
      "identifier": { "type": "android_package", "value": "com.cnn.mobile.android.phone" },
      "publisher_domain": "cnn.com",
      "impressions": 120000,
      "spend": 600.00
    }
  ],
  "by_property_truncated": false
}
  • identifier (required): {type, value} using the existing property identifier vocabulary. This is what the seller's ad server operationally knows (serving domain, app bundle), and it makes by_property rows directly consumable by validate_property_delivery - reporting output becomes governance input with metrics attached.
  • publisher_domain, property_id (optional): enrichment when the seller can resolve the identifier to a registered property, same SHOULD/MAY posture as by_placement.publisher_domain.

Capability: supports_property_breakdown boolean in reporting_capabilities, consistent with the other dimension flags.

Scope notes

  • Actuals only. This does not require products to enumerate property composition beyond what publisher_properties already declares. The ad server knows where impressions served even for run-of-network products. Once actuals exist, buyers also learn effective composition empirically.
  • Cardinality: run-of-network buys can span tens of thousands of properties. The existing limit/sort_by/truncated pattern handles this the same way it does for placement and postal-level geo.
  • Seller sensitivity: domain-level delivery can reveal supply mix. Capability-gating keeps it opt-in, same as every other dimension. Direct/guaranteed sellers already share site-level reporting in traditional IOs.
  • Per-dimension only: no cross-dimensional intersections, per the existing rule.

Open questions

  1. Is identifier the right required identity, with property_id/publisher_domain optional? (Alternative: require registry resolution, which adds seller burden and fails for unregistered properties.)
  2. Naming: property (channel-neutral, matches the property model) vs domain (web-biased). This RFC proposes property.
  3. Do windowed webhook payloads need parity, or is pull-only sufficient for optimization cadence (like other request-controlled dimensions)?
  4. Should there be a minimum-row threshold or other aggregation floor for sellers with privacy constraints?

Metadata

Metadata

Assignees

No one assigned

    Labels

    claude-triagedIssue has been triaged by the Claude Code triage routine. Remove to re-triage.media-buyIssue concerns the media-buy protocol domainneeds-wg-reviewBlocked on a working-group decision — surface in WG meeting agendasrfcProtocol change — auto-adds to roadmap boardspec / protocol

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    Status
    No status

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions