video_hosted format. They do not require a new canonical: the product narrows hosted video to a fixed duration and file specification with a single video slot. Network, station, daypart, clearance, and audience measurement are media-buy facts, not creative facts. Radio has its own guide.
Reference format declarations
The following :15, :30, and :60 declarations use a common US delivery profile: 16:9 at 1920×1080 or larger, 29.97 fps, MPEG-2 4:2:2 video with PCM audio in an MXF wrapper, and ATSC A/85 loudness (-24 LKFS ±2 dB, true peak -2 dBTP). A station or network may publish a different accepted profile (EBU R 128 loudness in Europe, for example), and the buyer matches the declaration it is offered rather than this one. See Delivery files for the file fields, including the experimentalloudness object.
:15 spot
:30 spot
:60 spot
duration_ms_exact.
Delivery files
Broadcast traffic systems ingest a mezzanine file, not a web-playable MP4. Avideo_hosted option narrows to that file with containers, video_codecs, and audio_codecs.
The codec slugs name codec families, not recording formats or profiles.
avc_intra and xavc are H.264-based but distinct from h264: a product that accepts h264 does not thereby accept them. Wrapper (containers) and bitrate bounds are declared separately; chroma subsampling, profile, and scan type are not machine-declarable on video_hosted yet, so a seller states them in the product description or its delivery spec sheet. Other mezzanine codecs (for example DNxHD) are not yet in the enum, and captions only states whether captions are required.
Loudness (experimental)
loudness states the audio loudness a delivered spot MUST meet. It is optional and experimental in AdCP 3.3, so sellers that populate it list creative.broadcast_loudness in experimental_features.
The three numeric fields carry the same semantics as
loudness_lufs, loudness_tolerance_db, and true_peak_dbfs on audio_hosted. standard labels the requirement; the numeric fields are what the receiver checks, and standard alone does not imply numeric values. Declare all three numeric fields when the requirement is to be checked.
Creative identifiers
Use the manifest’sindustry_identifiers list for the traffic or clearance identifier the broadcaster expects. AdCP supports ad_id, isci, clearcast_clock, and idcrea. Ad-ID is the common US television identifier; ISCI persists in some station traffic systems; Clearcast and IDcrea serve the UK and France. Choose the identifier your station’s traffic system keys on. A manifest may carry more than one identifier (for example both ad_id and isci when a traffic system still keys on ISCI). Each duration cut carries its own identifiers: the :15 and :30 versions of one spot are two creatives.
by_spot[].creative_id is the AdCP creative identifier you synced, and that creative’s manifest carries the industry_identifiers value the station’s traffic system keys on. by_spot rows do not carry the logged Ad-ID or ISCI themselves; the seller maps the logged identifier to your creative_id.
No VAST or tracker semantics
The reference declarations contain only the requiredvideo_main file slot. A linear spot is played out by the station’s automation system, where no VAST tag, impression pixel, click tracker, or clickthrough URL can operate. Their absence is part of the format contract; do not add tracker slots or represent these spots as video_vast.
Streaming and connected-TV inventory is a separate execution context. It may use video_hosted with explicitly declared trackers or video_vast for VAST delivery; see Video and CTV. A spot simulcast on a streaming service does not make trackers operational on the linear airing, and a linear buy’s counts do not come from trackers at all.
Networks, stations, and dayparts
Where a spot runs is described outside the creative, in three places:- Inventory — a product’s
publisher_propertiesselect properties from the seller’sadagents.json. Linear properties carrystation_id(a call sign),facility_id(a regulator-prefixed license such asfcc:73953), ornetwork_ididentifiers. Model the product by who commits the order: a network or rep-firm package is one product even when it fulfills across affiliates, while station-direct inventory is a product per selling station or group. See Broadcast TV package forecast. - Daypart on the buy —
daypart_targetson the package’s targeting overlay (days, atimezonewhereinventory_localevaluates each station’s own clock, and whole-hourstart_hour/end_hour) when the product supports it. Experimental in AdCP 3.3 (media_buy.daypart_granularity): an entry may instead carrystart_timeandend_timeasHH:MM, so a window such as 19:30–23:00 or a break at a programme junction is expressible. A product declares the finest clock it honors inoverlay_support.daypart_targets.time_granularity(hour,quarter_hour, orminute), and a seller rejects a finer time than it declares withUNSUPPORTED_FEATURErather than rounding. See Minute-resolution dayparts. - Daypart on the report —
dayparton aby_spotrow is a seller-defined label such asprime_timeorprime_access. There is no daypart enum, so a buyer reconciling across sellers compares the as-runaired_atagainst the daypart it bought rather than matching labels.
Delivery measurement and reconciliation
Linear TV plans and guarantees on measured audience: panel, set-top-box, and automatic-content-recognition data licensed from a currency or measurement provider, not served-event counts. What is invoiced depends on the pricing model. CPM and CPP bill on the currency count; a per-spot unit-rate buy bills on aired units, where the as-run log is the evidence of what aired. Acpm (or cpp) option with fixed_price is a fixed rate the seller sets; it is never a bid, and auction semantics apply only when fixed_price is absent, which broadcast sellers do not use. Three declarations carry the audience contract, and a fourth question (did it air?) is answered by separate evidence.
- Demographic notation —
demographic_systemanddemographicon the forecast (and on the CPP pricing option) say how the audience is written.nielsennotation isA25-54,P2+,W18-49. The enum also carriesvideoamp(age bands with an optional gender prefix, such asP25-54) andnmo(Netherlands: age bands such as25-67orM25-54); the notation strings for both are still being confirmed with the providers, so treat the examples as provisional. The worked example below writes its demo innielsennotation while VideoAmp counts it; a seller whose provider publishes its own notation declaresdemographic_system: "videoamp"instead. Notation is not a provider. - Provider identity —
measurement_sourceon forecast and delivery rows names whose data produced the numbers, as a lowercase slug (nielsen,videoamp,ispot). The samedemographic_system: "nielsen"notation can be measured by different providers. The contract names the billing vendor as a brand key ({ "domain": "videoamp.com" }, resolved through brand.json) inmeasurement_terms.billing_measurement.vendor(nielsen.com,videoamp.com,ispot.tv). A seller offering the same inventory under more than one currency publishes a forecast permeasurement_source; each forecast belongs to one product or proposal, so that means one per currency. - Maturation —
reporting_capabilities.measurement_windowsdeclares the stages:live(the airing day),c3(live plus three days of time-shifted viewing), andc7(live plus seven). A product typically marks one windowis_guarantee_basis: true, but which window a deal settles on is a term of the deal: read it frombilling_measurement.measurement_window, not from convention. A window’sexpected_availability_dayssays when the vendor publishes it; for C7 that is roughly two to three weeks after the airing. Until a row isis_final: truefor the billing window, the number is provisional and not an invoicing source; a later window supersedes an earlier one with its own provisional-to-final lifecycle. See Billing authority.
live and c3 undershoot c7. Use them for pacing, and do not invoice or declare a shortfall on a provisional row. Airings from different weeks of one flight mature on different days, so a buyer reconciling a long flight pulls date slices and reads each at the window it has reached.
Reconciliation contract
Two kinds of evidence come back, and they answer different questions.
The rules:
- Airing evidence is not a counting source. Station logs, affidavits, and playout records prove that a spot aired. The audience currency turns airings into the audience-size number. Never infer audience from airings, and never infer an airing from audience:
aired_atis what proves an airing. - As-run is reported apart from audience. A product that declares
supports_spot_breakdownwithavailable_metrics: []provides airing evidence only;by_spotrows then carry no audience numbers. A product may instead declare metrics at spot grain, which appear when a later window supersedes an earlier one. A guarantee and its invoice reconcile against package rows (and theby_demographicrow for the contracted demo), and the buyer does not rebuild package totals from spot rows. - Spot lifecycle is experimental and declared. In AdCP 3.3 a seller may also report
scheduled,preempted, andmakegoodrows throughby_spot[].spot_status, and says which it reports insupports_spot_breakdown.available_statuses(experimental,media_buy.spot_lifecycle). Onlyairedandmakegoodrows carryaired_atand prove an airing; ascheduledorpreemptedrow carriesscheduled_atinstead and is not airing evidence. A status the seller does not list proves nothing: the absence ofpreemptedrows is not evidence that nothing was preempted. See Optimization and reporting. spot_idis stable. The samespot_idis reported under Live, C3, and C7 (and, where the seller reports lifecycle, fromscheduledthroughairedorpreempted), so a buyer joins as-run evidence to later audience rows on it. Audience rows join on(media_buy_id, package_id, reporting_period, measurement_window).- Completeness is explicit.
by_spot_truncated: falsemeans the as-run log is complete for the period. A buyer reconciling airings requests the spot dimension without alimit. A seller that cannot attribute a creative to an airing omitscreative_idrather than guessing. - Who attests the airing is not declared. A buyer cannot tell a station traffic log from a third-party airing verification from the rows alone, and affidavit references are not carried on the wire today. Take both from the seller’s product description and the contract.
Worked example: a CPM impression guarantee on a demo
Pinnacle Media buys for Nova Brands from Harbor Broadcasting. Nova wants five million impressions among adults 25–54, delivered through :15 and :30 spots, counted by VideoAmp on the C7 window. The currency, window, and variance are agreed before the first spot airs.Today’s limits
This works today with four gaps. Read them before building on it:- The demo is bound on the forecast, not on the price. A CPM pricing option has no demographic parameters, unlike a CPP option (
parameters.demographic_system,demographic).measurement_terms.billing_measurementbinds the vendor, the window, and the variance, but has no demographic field. - The guaranteed volume has no typed definition.
purchases[].impressionsis the contracted volume, and a buyer can require a floor on it withrefine_proposalsconstraints.impressions(a hard minimum summed across purchases). The schema does not say that number counts measured audience, in which demo, from which vendor, or on which window. Those facts sit on the forecast andbilling_measurement, and the forecast is outsidecommercial_terms, so it is not covered byterms_digest. Treat the demo as a term agreed in the human contract outside AdCP, not one a protocol agent can verify. - :30 equivalization is not expressible. Nothing declares whether a :15 impression counts as half a :30 unit or the factor to apply. A CPM prices impressions regardless of unit length, so on a buy that mixes :15 and :30 spots the equivalization rule is a term to settle outside the protocol.
- No under-delivery trigger, and the schedule on the wire is experimental.
makegood_policydoes not name a volume shortfall as a trigger. A seller may report the planned schedule asscheduledrows inby_spot, but that field is experimental and seller-declared, so a buyer cannot assume one. See Makegoods.
1. The seller publishes the product
The product is alinear_tv package with two video_hosted format options, one CPM price, and the measurement it will stand behind. VideoAmp is the billing vendor and C7 is the guarantee window. The final C7 record is due within 360 hours of the window closing, and the seller publishes it on get_media_buy_delivery. supports_spot_breakdown.available_metrics is empty, so spot rows are airing evidence only. The seller also declares the experimental spot lifecycle (available_statuses) and break position (supports_break_position), and lists media_buy.spot_lifecycle in experimental_features on get_adcp_capabilities.
2. The buyer asks for the outcome
The buyer fixes the goal and volume, and states the demo in the brief because the goal cannot carry it. Sendcriteria.outcome_target only to a seller that declares media_buy.outcome_target in get_adcp_capabilities; a seller that does not rejects the structured form with UNSUPPORTED_FEATURE, and the buyer falls back to the brief alone. cost_per is not sent: it is rejected on measured_impressions, and the CPM rate is the price. The goal is a planning input, not a guarantee.
3. The seller’s proposal carries the contract
The draft states the guaranteed volume, the price, the formats, and the agreed measurement terms on the purchase. Finalizing and accepting it (refine_proposals, accept_proposal) commits commercial_terms. The forecast repeats the demo and the currency so delivery rows can be compared against it, but it is not part of the committed terms and its numbers may change between draft and committed proposal.
measured_impressions is the same count that delivery reports as impressions with a measurement_source; in a forecast, plain impressions means the seller’s own ad-server count.
To change a measurement term (a different vendor or window, a different variance), the buyer states the change in refine_proposals ask and reads the revised commercial_terms and terms_digest; there is no typed measurement-terms input on refinement. The deprecated create_media_buy path instead returns TERMS_REJECTED for a term the seller cannot support; see Accountability.
If the seller confirms through a booking round or sales-desk review, accept_proposal returns a submitted arm that may carry expected_confirmation_at (added in 3.3), an estimate of when to check back. It is not a commitment, so schedule a status check for that time rather than polling tightly. Once accept_proposal returns the media buy and its purchase_bindings[], the buyer syncs each cut with sync_creatives, carrying its own identifier as in Creative identifiers, and assigns it to the package. Station clearance and delivery deadlines are outside the protocol.
4. Delivery: as-run first, audience later
The buyer reads delivery with the demographic breakdown for the contracted demo and the spot breakdown. A reconciliation pull omits the spotlimit so the log is complete; this example caps it at four rows to stay short.
is_final: false. As-run evidence is available from the first reporting cycle, about 48 hours after an airing (expected_delay_minutes). Once C7 closes and the vendor publishes, the seller reports the settled row:
5. Reconciliation
The buyer reconciles two streams, each against its own evidence:- Did it air? Start from the schedule. This seller reports
scheduledrows (experimental, declared inavailable_statuses), so the planned spots arrive on the wire and eachspot_idlater resolves to anairedrow or apreemptedrow. A seller that does not declarescheduledleaves the schedule outside the protocol, in the buyer’s traffic confirmation or the contract. Compare it against the completeby_spotlog (by_spot_truncated: false). A scheduled spot that resolves to a row withaired_atis evidenced. Apreemptedrow did not air, and the log here shows the replacement:spot_0431is amakegoodrow whosereplaces_spot_idisspot_0408. A scheduled spot with no row at all is unevidenced, and it is the basis for a makegood claim.creative_idanddayparton each aired row confirm that the right cut ran in the daypart the buyer bought, andbreak_position(experimental,supports_break_position) places the spot in its break. None of this involves an audience number. - How many people? Read the
by_demographicrow for the contracted demo (A25-54innielsennotation, with theageinterval echoed) and confirmby_demographic_suppressedis false. The package row must match the agreedbilling_measurement:measurement_window: "c7"withis_final: trueandmeasurement_source: "videoamp". The package row carries no demographic of its own, so theby_demographicrow is how the buyer confirms the number is for the demo. 4,870,000 against the 5,000,000 guarantee is a shortfall of 130,000 impressions. - What is billed? This example bills delivered impressions at the CPM, capped at the purchase
budget: 4,870,000 ÷ 1,000 × $32 = $155,840, thespendon the final row. Over-delivery is not billed beyond the cap. That convention is a term of the deal.max_variance_percentis not a tolerance on the shortfall against the guarantee; it bounds how far two counts of the same thing may diverge before resolution is triggered. A buyer that holds its own VideoAmp or iSpot subscription reports its count withreport_usage, as described in Billing authority. - Is the shortfall remedied? The invoice above already prices out the 130,000 impressions, so an
invoice_adjustmentwould be redundant here. Whether a volume shortfall triggers a remedy at all is a term of the deal (see Makegoods);additional_deliverywould fill toward the guarantee andcreditwould carry the value forward.
finalization_deadline_hours, counted from the close of the C7 window), the counterparty may fall back to its own attestation for invoicing. After the deadline the buyer is exposed: the seller’s own attestation could rest on provisional Live or C3 numbers, which understate C7. Set the deadline to match the vendor’s published availability, and watch expected_availability on the delivery row (or a reporting_delayed webhook) before it elapses.
Makegoods
measurement_terms.makegood_policy.available_remedies is a menu the seller commits to, ordered by seller preference: additional_delivery (extra airings), credit (a credit toward future buys on the account), and invoice_adjustment (a reduced invoice). A buyer proposing a remedy the seller does not support is rejected with TERMS_REJECTED at negotiation. The schema names performance-standard breaches, billing-variance breaches, and missed finalization deadlines as triggers. A volume shortfall against a guarantee is not among them, so whether and how it triggers a remedy is a term of the deal outside the protocol. Proposing, accepting, and disputing a remedy also happen out of band.
Report-time spot lifecycle (experimental in AdCP 3.3). A seller that declares media_buy.spot_lifecycle in experimental_features can report a preemption and its replacement in by_spot:
- A spot keeps one
spot_idas it moves fromscheduledtoairedor topreempted.scheduled_atcarries the planned slot (for a preempted row, the slot that was lost), and a preempted row has noaired_at. - A
makegoodrow is a separate airing with its ownspot_id, anaired_at, and areplaces_spot_idnaming the preempted spot. A planned replacement is ascheduledrow that already carriesreplaces_spot_id, so the buyer sees the link before it airs. - The seller lists the statuses it reports in
supports_spot_breakdown.available_statuses. A status that is not listed proves nothing, so a buyer must not read missingpreemptedormakegoodrows as “nothing was preempted”. A preemption surfaces as apreemptedrow on the next report; there is no separate notification, and a seller does not send these rows to callers pinned below 3.3.
get_media_buy_delivery, and Creative manifests.