diff --git a/.changeset/dooh-placement-attributes.md b/.changeset/dooh-placement-attributes.md new file mode 100644 index 0000000000..9c539aa86e --- /dev/null +++ b/.changeset/dooh-placement-attributes.md @@ -0,0 +1,5 @@ +--- +"adcontextprotocol": minor +--- + +Add DOOH structured selling-unit fields to placements: `dooh_placement_attributes` (slot_duration_seconds, loop_duration_seconds, screen_resolution, motion) and `identifiers[]` on both placement.json and placement-definition.json. New `dooh-motion-type` enum. Supersede pricing-layer loop_duration_seconds in flat-rate-option.json. diff --git a/docs/media-buy/product-discovery/media-products.mdx b/docs/media-buy/product-discovery/media-products.mdx index 0c2b89ed74..ba34fff408 100644 --- a/docs/media-buy/product-discovery/media-products.mdx +++ b/docs/media-buy/product-discovery/media-products.mdx @@ -277,6 +277,21 @@ The field is an array because a sellable product can aggregate multiple surfaces This is a discovery signal, not a verification claim. Buyers can filter for products that can satisfy a requested surface with `get_products.filters.social_placement_surfaces`, but sellers should not return mixed, non-targetable bundles unless they can constrain delivery to the requested surface during planning or purchase. +#### DOOH placement attributes + +Digital out-of-home placements can declare structured selling-unit metadata via `dooh_placement_attributes` at the placement level (both in product placements and in `adagents.json` placement definitions). These fields describe the physical screen and ad-loop characteristics that buyers need for creative production and share-of-voice calculations: + +| Field | Type | Meaning | +|---|---|---| +| `slot_duration_seconds` | integer | Duration of one ad slot in seconds (e.g., 10, 15, 30) | +| `loop_duration_seconds` | integer | Duration of the full ad loop rotation in seconds. Buyers derive nominal slot share as `slot_duration_seconds / loop_duration_seconds`. This is the canonical source; the pricing-layer field in `flat-rate-option` is superseded | +| `screen_resolution` | object | Physical screen resolution (`{ width, height }` in pixels). Buyers derive aspect ratio from `width / height` | +| `motion` | string | Motion capability of the screen: `full_motion` (video), `partial_motion` (animated stills), or `static` (images only) | + +All fields are optional. A single screen/frame placement can include all fields; a package or network placement should include only fields that are uniform across the included inventory. + +Placements can also carry `identifiers[]` using the same `{ type, value }` shape as property identifiers. DOOH placements commonly use `venue_id`, `screen_id`, and `openooh_venue_type` identifier types. Externally governed IDs should be authority-prefixed (e.g., `geopath:30961`). + #### Format precedence with placements Product-level `format_ids` and `format_options` define the creative formats accepted by the product as a whole. Placement-level `format_ids` or `format_options`, whether returned inline on the product placement or inherited from a public publisher placement declaration, only narrow that product-wide set for the specific placement. diff --git a/static/schemas/source/core/placement-definition.json b/static/schemas/source/core/placement-definition.json index 6a99f89b6a..593d0744ee 100644 --- a/static/schemas/source/core/placement-definition.json +++ b/static/schemas/source/core/placement-definition.json @@ -121,6 +121,65 @@ "uniqueItems": true, "minItems": 1 }, + "identifiers": { + "type": "array", + "description": "Optional external inventory identifiers for this placement, using the same {type, value} shape as property identifiers. Externally governed IDs should be authority-prefixed (e.g., space:1234931339, geopath:30961, fcc:73953). Seller-local IDs are opaque values scoped by the surrounding publisher namespace. Product-level placement declarations may carry additional identifiers but SHOULD NOT contradict publisher-declared identifiers for the same type.", + "items": { + "type": "object", + "properties": { + "type": { + "$ref": "/schemas/enums/identifier-types.json" + }, + "value": { + "type": "string", + "description": "Identifier value, optionally authority-prefixed for externally governed IDs (e.g., space:1234931339)." + } + }, + "required": ["type", "value"], + "additionalProperties": false + }, + "uniqueItems": true, + "minItems": 1 + }, + "dooh_placement_attributes": { + "type": "object", + "description": "DOOH-specific placement metadata for digital out-of-home inventory. Each field is optional and should only be populated when it is true for the placement being represented. A single screen/frame placement can include all fields; a package/network placement should include fields only when they are uniform across the included inventory. Product-level placement declarations may narrow these attributes but SHOULD NOT broaden them.", + "properties": { + "slot_duration_seconds": { + "type": "integer", + "description": "Duration of one ad slot in seconds (e.g., 10, 15, 30). Aligns with the seconds-based duration convention used by loop_duration_seconds.", + "minimum": 1 + }, + "loop_duration_seconds": { + "type": "integer", + "description": "Duration of the full ad loop rotation in seconds. Buyers can derive nominal slot share as slot_duration_seconds / loop_duration_seconds. This is the canonical source for loop duration; the pricing-layer field in flat-rate-option.json is superseded by this placement-level declaration.", + "minimum": 1 + }, + "screen_resolution": { + "type": "object", + "description": "Physical screen resolution in pixels. Buyers can derive aspect ratio from width/height.", + "properties": { + "width": { + "type": "integer", + "description": "Screen width in pixels.", + "minimum": 1 + }, + "height": { + "type": "integer", + "description": "Screen height in pixels.", + "minimum": 1 + } + }, + "required": ["width", "height"], + "additionalProperties": false + }, + "motion": { + "$ref": "/schemas/enums/dooh-motion-type.json", + "description": "Motion capability of the DOOH screen. Determines whether full-motion video, partial-motion (animated stills), or static-only creatives are accepted." + } + }, + "additionalProperties": true + }, "ext": { "$ref": "/schemas/core/ext.json" } diff --git a/static/schemas/source/core/placement.json b/static/schemas/source/core/placement.json index eb1627aeee..90c6df5ecb 100644 --- a/static/schemas/source/core/placement.json +++ b/static/schemas/source/core/placement.json @@ -92,6 +92,65 @@ }, "uniqueItems": true, "minItems": 1 + }, + "identifiers": { + "type": "array", + "description": "Optional external inventory identifiers for this placement, using the same {type, value} shape as property identifiers. Externally governed IDs should be authority-prefixed (e.g., space:1234931339, geopath:30961, fcc:73953). Seller-local IDs are opaque values scoped by the surrounding publisher namespace. Useful for DOOH screen/venue IDs, broadcast facility IDs, and any channel where placements map to externally registered inventory.", + "items": { + "type": "object", + "properties": { + "type": { + "$ref": "/schemas/enums/identifier-types.json" + }, + "value": { + "type": "string", + "description": "Identifier value, optionally authority-prefixed for externally governed IDs (e.g., space:1234931339)." + } + }, + "required": ["type", "value"], + "additionalProperties": false + }, + "uniqueItems": true, + "minItems": 1 + }, + "dooh_placement_attributes": { + "type": "object", + "description": "DOOH-specific placement metadata for digital out-of-home inventory. Each field is optional and should only be populated when it is true for the placement being represented. A single screen/frame placement can include all fields; a package/network placement should include fields only when they are uniform across the included inventory.", + "properties": { + "slot_duration_seconds": { + "type": "integer", + "description": "Duration of one ad slot in seconds (e.g., 10, 15, 30). Aligns with the seconds-based duration convention used by loop_duration_seconds.", + "minimum": 1 + }, + "loop_duration_seconds": { + "type": "integer", + "description": "Duration of the full ad loop rotation in seconds. Buyers can derive nominal slot share as slot_duration_seconds / loop_duration_seconds. This is the canonical source for loop duration; the pricing-layer field in flat-rate-option.json is superseded by this placement-level declaration.", + "minimum": 1 + }, + "screen_resolution": { + "type": "object", + "description": "Physical screen resolution in pixels. Buyers can derive aspect ratio from width/height.", + "properties": { + "width": { + "type": "integer", + "description": "Screen width in pixels.", + "minimum": 1 + }, + "height": { + "type": "integer", + "description": "Screen height in pixels.", + "minimum": 1 + } + }, + "required": ["width", "height"], + "additionalProperties": false + }, + "motion": { + "$ref": "/schemas/enums/dooh-motion-type.json", + "description": "Motion capability of the DOOH screen. Determines whether full-motion video, partial-motion (animated stills), or static-only creatives are accepted." + } + }, + "additionalProperties": true } }, "required": [ diff --git a/static/schemas/source/enums/dooh-motion-type.json b/static/schemas/source/enums/dooh-motion-type.json new file mode 100644 index 0000000000..7831d2f9aa --- /dev/null +++ b/static/schemas/source/enums/dooh-motion-type.json @@ -0,0 +1,21 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/schemas/enums/dooh-motion-type.json", + "title": "DOOH Motion Type", + "description": "Motion capability of a digital out-of-home screen. Determines which creative formats the screen can render.", + "type": "string", + "enum": [ + "full_motion", + "partial_motion", + "static" + ], + "enumDescriptions": { + "full_motion": "Screen supports full-motion video playback (e.g., LED billboards, transit screens with video capability)", + "partial_motion": "Screen supports animated stills or limited motion (e.g., scrolling text, animated GIFs, HTML5 banners) but not full video", + "static": "Screen displays static images only (e.g., e-ink displays, printed poster replacements)" + }, + "examples": [ + "full_motion", + "static" + ] +} diff --git a/static/schemas/source/enums/identifier-types.json b/static/schemas/source/enums/identifier-types.json index 0b6bf40e4b..d8554c641a 100644 --- a/static/schemas/source/enums/identifier-types.json +++ b/static/schemas/source/enums/identifier-types.json @@ -1,8 +1,8 @@ { "$schema": "http://json-schema.org/draft-07/schema#", "$id": "/schemas/enums/identifier-types.json", - "title": "Property Identifier Types", - "description": "Valid identifier types for property identification across different media types", + "title": "Identifier Types", + "description": "Valid identifier types for property and placement identification across different media types", "type": "string", "enum": [ "domain", diff --git a/static/schemas/source/pricing-options/flat-rate-option.json b/static/schemas/source/pricing-options/flat-rate-option.json index 413348a486..6abecfd497 100644 --- a/static/schemas/source/pricing-options/flat-rate-option.json +++ b/static/schemas/source/pricing-options/flat-rate-option.json @@ -52,7 +52,7 @@ }, "loop_duration_seconds": { "type": "integer", - "description": "Duration of the ad loop rotation in seconds", + "description": "Duration of the ad loop rotation in seconds. NOTE: this pricing-layer field is superseded by the placement-level dooh_placement_attributes.loop_duration_seconds, which is the canonical source. Retain here for backward compatibility; new integrations should read the placement-level field.", "minimum": 1 }, "min_plays_per_hour": {