Overview
For a media buy to invoice deterministically, two questions must have machine-readable answers:- Whose number is authoritative? Different deals name different parties — the seller’s ad server, a buyer’s third-party ad server, or a named measurement vendor like Nielsen or IAS.
- Has that number stopped moving? Telemetry settles over hours, days, or weeks (broadcast C3 → C7 DVR accumulation, digital post-IVT scrubbing, podcast 30-day downloads, conversion dedup). Final numbers are billable; provisional numbers are not.
measurement_terms.billing_measurement (negotiated at create_media_buy) names authority; is_final / final flags with finalized_at timestamps (on get_media_buy_delivery and report_usage) mark closure.
This page ties those pieces together.
Billing authority and Reliable Reporting are separate contracts today.
Reliable Reporting
(experimental in 3.2) answers a different question: did the report I was
promised arrive, intact, on time? It gives the seller-produced feed
obligations, immutable revisions, a binding digest, health states, and — when
the seller opts in — a buyer-to-seller
sync_reporting_status
loop. None of that decides whose count governs the invoice, which is what
this page’s billing_measurement does.So both surfaces can read green while an invoice is still disputed: a buyer’s
consumer status can be received and the seller’s health complete on a feed
whose numbers sit outside max_variance_percent of the authoritative party’s.
reporting-delivery-config.json reserves an authoritative_party field
(seller | consumer, default seller) so the two models can be unified
additively. In 3.2 the only accepted value is seller; sellers MUST reject
consumer with UNSUPPORTED_FEATURE because no released minor defines the
buyer-deposited revision task. Tracked in
#7440.Naming authority
measurement_terms.billing_measurement carries:
Absence is informative: when
billing_measurement is absent the default is seller-attested, with no contractual finalization deadline.
Declaring how the billing count is built (experimental)
Experimental in 3.3 (feature id
media_buy.measurement_provenance). counting_mechanisms[] and the collection-mechanism enum may change within 3.x with the notice described in Experimental status. Sellers that emit it declare the feature id in experimental_features.billing_measurement.vendor and still count differently: one bills from server-side delivery logs, another from begin-to-render beacons. When variance later exceeds max_variance_percent, a common cause is that difference, and it was never on the wire. counting_mechanisms[] puts it there before the buy, so a buyer agent can compare declared mechanisms across products (client-side on measurement_terms; a get_products filter is an additive follow-up) and the field is part of what gets negotiated.
- Billing count only. It lists the mechanisms whose events enter the billed number. Mechanisms used only for audit or cross-check are not listed. If several are listed, the merge rule is not encoded; the seller describes it in its methodology. Provenance on individual reported vendor values is
vendor_metric_provenance, which shares the vocabulary. Neither field ismeasurement_source, which names the provider. - A claim, not a probe. It is a claim by the declaring party, enforced through the contract (
vendor,max_variance_percent,makegood_policy) rather than tested by AdCP. A count that materially differs from what was declared is handled like any other variance under those terms. - Absence means undeclared. Never read an absent field as
server_logsor any other default. It is declared alongsidevendor; a seller that omitsbilling_measurementdeclares nothing. - Self-counting sellers SHOULD declare it. When the seller (or its ad server) is the named
vendor, declarecounting_mechanisms[]. Buyer-attested and third-party vendors describe their own method in their measurement-agent catalog and MAY omit it. - Negotiable like any other term. On a product it is the seller’s default; on a package request it is a buyer’s proposed term; the seller accepts, adjusts, or rejects with
TERMS_REJECTED. In practice a seller will rarely agree to a different method for its own count, so treat it as a handshake more than a lever. - A set. Order carries no meaning and values MUST NOT repeat.
- Airing evidence is not a counting mechanism. Broadcast as-run logs and station affidavits prove that a spot ran; they are not a mechanism for audience measurement and have no value in this vocabulary. Delivery reports carry as-run data in
by_spot[], separate from the audience rows thatcounting_mechanisms[]andvendor_metric_provenancedescribe.
Product excerpt — a CTV seller billing from its server-side logs
client_tracker) can see from this declaration that its count will run below the seller’s, and a gap inside the stated variance is expected rather than disputed. The buyer can instead propose its own ad server as billing_measurement.vendor on the package request.
Marking numbers as final
Final means settled for the named measurement window — not “final forever.” A broadcast row markedis_final: true for measurement_window: "c3" is final for C3; a later c7 row supersedes it with its own provisional → final lifecycle. A future structured dispute would join on (media_buy_id, reporting_period, measurement_window); 3.2 does not define one.
On get_media_buy_delivery
Each row in media_buy_deliveries[] carries:
is_final: boolean— row-level finality, equivalent to all packages in the row being final for the same window.finalized_at: string (date-time)— present iffis_final: true. Anchors any deadline declared inbilling_measurement.finalization_deadline_hours.- Per-package:
by_package[*].is_final,by_package[*].finalized_at,by_package[*].measurement_window,by_package[*].supersedes_window.
On report_usage
Predecessor path. For media-buy billing,
report_usage is the
pre-Reliable-Reporting channel for buyer- and vendor-attested numbers. It has no
obligations, no immutable revisions, no RFC 8785/JCS binding digest, no
supersession chain, and no status surface, so a missing or restated settlement
file is not detectable on the wire the way a missing reporting obligation is.
It remains the supported path for the buyer-attested and vendor-attested flows
below until a buyer-deposited revision task exists
(#7440). Non-media-buy
report_usage variants (signals, governance, creative, brand) are unaffected
and are not superseded by Reliable Reporting.final: boolean— absent means unknown. Settrueonly when the reporter has actually settled the numbers (e.g., post-SIVT month-end close). Setfalsefor preliminary records (daily pacing pushes, intra-period progress). Whenmeasurement_terms.billing_measurementnames this reporter as authoritative, the receiver MUST NOT invoice onfinal: falseor absent — request a final record first. For 3.0-style usage with nobilling_measurementand for non-media-buy variants (signals, governance, creative, brand — domains with no provisional state concept), receivers MAY treat absent as final, preserving existing behavior.finalized_at: string (date-time)— present ifffinal: true.measurement_window: string— SHOULD be set when the buy’sbilling_measurement.measurement_windowis set, so the receiver reconciles against the correct stage.
(account, media_buy_id, reporting_period) is later reported with final: true, that record supersedes any prior records for the period.
Distinguishing webhook finality from row finality
get_media_buy_delivery webhooks carry a top-level notification_type enum that includes "final" — this signals “this is the last scheduled notification for the campaign,” not that contained rows are final for invoicing. The two axes are independent: a webhook with notification_type: "final" may still contain rows where is_final: false (e.g., a campaign-end notification before C7 settles). Always check the per-row is_final for billing decisions.
How a seller produces an invoice
Seller-attested (default)
get_media_buy_delivery rows where is_final: true for the contracted measurement_window. No report_usage from the buyer is required.
Buyer-attested (3PAS)
- Buyer’s CM360 settles post-SIVT for the period.
- The buyer’s operator — in practice a holdco platform (e.g., Choreograph, Annalect, Acxiom) or an in-house agency engineering team that wraps the CM360 export — calls
report_usagewith the media-buy record:media_buy_id,impressions,vendor_cost,currency,final: true,finalized_at,measurement_window: "post_sivt". Daily pacing pushes (if used) setfinal: false; only the settled file setsfinal: true. - Seller compares against its own post-SIVT row from
get_media_buy_delivery(is_final: true, samemeasurement_window). If|seller - buyer| / max ≤ max_variance_percent, the seller invoices on the buyer’s numbers. - If variance exceeds threshold, the seller proposes a remedy from
makegood_policy.available_remedies. - If the buyer doesn’t publish a final record within
finalization_deadline_hours, the seller MAY invoice off its own seller-attested numbers and treat the late finalization as a breach undermakegood_policy.
Today’s reality: monthly 3PAS reconciliation is mostly handled out-of-band via CSV/PDF emailed to the seller’s AR team. This flow is the wire-format upgrade — the first adopters are likely holdco operators with the engineering to wrap CM360 / Flashtalking / Innovid exports in report_usage, working with sympathetic direct publishers rather than RTB SSPs.
Vendor-attested (named third party)
- Seller holds the vendor relationship (the common CTV pattern). The seller pulls C7 numbers from Nielsen (NPower, etc.) on its own schedule and publishes them on
get_media_buy_deliveryas a row withmeasurement_window: "c7",is_final: true, andfinalized_atset when the C7 window closes plus its internal processing. Noreport_usagepush from the buyer is needed; reconciliation happens against the seller’s row. - Buyer holds the vendor relationship. The buyer (or its operator) fetches the vendor’s authoritative numbers — e.g., an agency’s iSpot subscription, an in-house IAS dashboard export — and pushes them via
report_usageagainst the buy’s account withfinal: true,finalized_at, andmeasurement_window: "c7". The vendor itself does not call AdCP.
vendor.domain BrandRef identifies who the contract names, not who calls the API. The vendor’s own integration (NPower feed, IAS API, DV pinnacle) is out of AdCP scope.
Today’s reality: SSPs running RTB will keep being seller-attested for the foreseeable future — their billing systems were never designed for buyer-attested invoice basis andmax_variance_percentplusmakegood_policyis not enough commercial cover for them to retrofit it. The first real adopters here are CTV direct sellers (e.g., Disney, NBCU, Paramount) whose Nielsen-backed guarantees already invoice on a measurement vendor’s count — for them this PR just describes existing practice in structured terms.
Resolving disagreements today
When numbers disagree beyondmax_variance_percent, AdCP 3.0–3.1 expects out-of-band resolution between counterparties, backed by:
- The buy’s
makegood_policy.available_remedies— the menu of remedies (additional delivery, credit, invoice adjustment) the seller has pre-committed to. - Final records on both sides with
finalized_attimestamps — a full audit trail of who said what was final, when. - The original
committed_metricsandmeasurement_termscaptured atcreate_media_buy— what the parties signed up for.
under_review / seller_proposed_adjustment / buyer_accepted / unresolved_arbitration, and recording resolution in the audit log — does not exist in 3.2 and is not scheduled for it. The data shape needed to dispute (final records, attestation, measurement window, makegood menu) is already on the wire in 3.1, and Reliable Reporting has since added the first piece of the eventual lifecycle: reporting-status-issue.json carries issue_state (open / acknowledged / resolved / waived), opened_at, and an inert external_ref for correlation with each side’s own ticketing. A shared dispute lifecycle built on those fields is tracked in #7440.
A variance beyond max_variance_percent is not a
sync_reporting_status content_mismatch. That consumer status is reserved
for contract facts the accepted reporting configuration generation already
fixed — a frozen media buy missing from the denominator, a promised metric
absent, the wrong currency. A disagreement about how many impressions occurred
is a measurement dispute and stays here, under makegood_policy.
Worked example: buyer-attested 3PAS reconciliation
create_media_buy excerpt — measurement terms
get_media_buy_delivery — seller's final post-SIVT row
report_usage — buyer's final 3PAS push
|5120000 - 5040000| / 5120000 = 1.56% — well under the 10% threshold. Seller invoices on the buyer’s 5.04M impressions × the agreed rate. Both sides retain audit-traceable final records.
Related
measurement-terms— schemaget_media_buy_delivery— seller-side finality flagsreport_usage— buyer-side / third-party finality flags- Accountability — performance standards, makegood remedies, cancellation
- Reporting capabilities and measurement windows
- Reliable Reporting: implementing
reporting.core— the operational delivery contract for the seller-produced feed sync_reporting_status— buyer-to-seller consumption status, and why it is not a dispute channel