Problem
video_hosted and audio_hosted can express an exact duration (duration_ms_exact) or a closed range (duration_ms_range: [min, max]), but not a single open bound — i.e. "up to N seconds" or "at least N seconds." The common real-world constraint is a ceiling ("≤30s audio," "≤60s video"), which today has nowhere clean to go: you must either fake an exact value or invent a lower bound ([0, 30000] / [1, 30000]), both of which misstate the contract.
Current state (3.1.0-rc.4)
formats/canonical/video_hosted.json duration params: duration_ms_range, duration_ms_exact — no bare min/max.
formats/canonical/audio_hosted.json duration params: duration_ms_range, duration_ms_exact — no bare min/max.
formats/canonical/image_carousel.json already has a bare card_video_max_duration_ms — so the bare-max pattern is already blessed in one canonical; it's just inconsistent across the others.
Why this matters — evidence
Implementing the Spotify standard audio ad ("up to 30 seconds"), we had to publish it as duration_ms_exact: 30000 because a max-only "≤30s" had no field — overstating it as exactly 30s. The same gap hits social video caps (TikTok / Snap / Reels "up to N seconds").
Proposed change
Add optional min_duration_ms and max_duration_ms to video_hosted and audio_hosted params, alongside the existing duration_ms_range / duration_ms_exact, matching the bare-max precedent already in image_carousel.card_video_max_duration_ms.
Documented resolution precedence: duration_ms_exact (fixed) → duration_ms_range (closed) → bare min_duration_ms / max_duration_ms (open bound; either or both).
Affected files
static/schemas/src/formats/canonical/video_hosted.json
static/schemas/src/formats/canonical/audio_hosted.json
docs/creative/canonical-formats.mdx — duration field precedence
What this is NOT
- Non-breaking: purely additive optional fields; existing
duration_ms_exact / duration_ms_range unchanged.
Filed from implementer experience maintaining AdCP community-mirror catalogs.
Problem
video_hostedandaudio_hostedcan express an exact duration (duration_ms_exact) or a closed range (duration_ms_range: [min, max]), but not a single open bound — i.e. "up to N seconds" or "at least N seconds." The common real-world constraint is a ceiling ("≤30s audio," "≤60s video"), which today has nowhere clean to go: you must either fake an exact value or invent a lower bound ([0, 30000]/[1, 30000]), both of which misstate the contract.Current state (3.1.0-rc.4)
formats/canonical/video_hosted.jsonduration params:duration_ms_range,duration_ms_exact— no bare min/max.formats/canonical/audio_hosted.jsonduration params:duration_ms_range,duration_ms_exact— no bare min/max.formats/canonical/image_carousel.jsonalready has a barecard_video_max_duration_ms— so the bare-max pattern is already blessed in one canonical; it's just inconsistent across the others.Why this matters — evidence
Implementing the Spotify standard audio ad ("up to 30 seconds"), we had to publish it as
duration_ms_exact: 30000because a max-only "≤30s" had no field — overstating it as exactly 30s. The same gap hits social video caps (TikTok / Snap / Reels "up to N seconds").Proposed change
Add optional
min_duration_msandmax_duration_mstovideo_hostedandaudio_hostedparams, alongside the existingduration_ms_range/duration_ms_exact, matching the bare-max precedent already inimage_carousel.card_video_max_duration_ms.Documented resolution precedence:
duration_ms_exact(fixed) →duration_ms_range(closed) → baremin_duration_ms/max_duration_ms(open bound; either or both).Affected files
static/schemas/src/formats/canonical/video_hosted.jsonstatic/schemas/src/formats/canonical/audio_hosted.jsondocs/creative/canonical-formats.mdx— duration field precedenceWhat this is NOT
duration_ms_exact/duration_ms_rangeunchanged.Filed from implementer experience maintaining AdCP community-mirror catalogs.