Skip to main content

Overview

For a media buy to invoice deterministically, two questions must have machine-readable answers:
  1. 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.
  2. 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.
AdCP answers both with structured terms already on the wire: 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.

Marking numbers as final

Final means settled for the named measurement window — not “final forever.” A broadcast row marked is_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 iff is_final: true. Anchors any deadline declared in billing_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.
Each usage record carries:
  • final: boolean — absent means unknown. Set true only when the reporter has actually settled the numbers (e.g., post-SIVT month-end close). Set false for preliminary records (daily pacing pushes, intra-period progress). When measurement_terms.billing_measurement names this reporter as authoritative, the receiver MUST NOT invoice on final: false or absent — request a final record first. For 3.0-style usage with no billing_measurement and 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 iff final: true.
  • measurement_window: string — SHOULD be set when the buy’s billing_measurement.measurement_window is set, so the receiver reconciles against the correct stage.
When the same (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)

Seller invoices off 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)

Sequence:
  1. Buyer’s CM360 settles post-SIVT for the period.
  2. 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_usage with the media-buy record: media_buy_id, impressions, vendor_cost, currency, final: true, finalized_at, measurement_window: "post_sivt". Daily pacing pushes (if used) set final: false; only the settled file sets final: true.
  3. Seller compares against its own post-SIVT row from get_media_buy_delivery (is_final: true, same measurement_window). If |seller - buyer| / max ≤ max_variance_percent, the seller invoices on the buyer’s numbers.
  4. If variance exceeds threshold, the seller proposes a remedy from makegood_policy.available_remedies.
  5. 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 under makegood_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)

Two operational patterns, depending on who holds the vendor relationship:
  • 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_delivery as a row with measurement_window: "c7", is_final: true, and finalized_at set when the C7 window closes plus its internal processing. No report_usage push 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_usage against the buy’s account with final: true, finalized_at, and measurement_window: "c7". The vendor itself does not call AdCP.
The 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 and max_variance_percent plus makegood_policy is 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 beyond max_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_at timestamps — a full audit trail of who said what was final, when.
  • The original committed_metrics and measurement_terms captured at create_media_buy — what the parties signed up for.
A structured dispute task — opening a dispute on the wire, transitioning it through 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
Variance: |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.