Repository navigation
[Change] § 5.6 — Give cost_method an extensible vocabulary, and say what several pricing[] entries mean #94
Description
What kind of change?
Change a field's type or shape
Which section?
5.6 — Commercial terms
Current text
| `pricing[]` | Array[Object] | mixed | See below |
| `pricing[].cost_method` | Enum | seller-set | CPM, CPC, flat, etc. |Proposed text
§ 5.6, replace the cost_method row with:
| `pricing[].pricing_id` | String | immutable | Names the entry. Never reused for another `cost_method`, `cost_parameters`, `currency`, or `transaction_mechanisms[]` |
| `pricing[].cost_method` | String | seller-set | The billable unit: a core term (Cost methods, below), or an extension term `<domain>:<name>` |
| `pricing[].rate_per` | Number | seller-set | REQUIRED for an extension term. Units per rate: `1` or `1000` |
| `pricing[].unit` | String | seller-set | REQUIRED for an extension term. A short label for one unit, such as `engagement` |
| `pricing[].cost_definition` | String (URL) | seller-set | REQUIRED for an extension term. Public definition of one unit and the `cost_parameters` keys, on the term's prefix domain or a subdomain |
| `pricing[].cost_parameters` | Object | seller-set | The keys the term requires |
| `pricing[].transaction_mechanisms[]` | Array[Enum] | seller-set | OPTIONAL. Mechanisms this entry prices. Absent: all offered |
After the table:
`pricing[]` entries are alternatives. The buyer commits under exactly
one, named by `commitment.pricing_id`; it MUST cover the selected
mechanism. Only that entry enters `agreed_rate`, `derived_units`, and the
`floor` comparison. Two entries MUST NOT share `cost_method`,
`cost_parameters`, `currency`, and a mechanism.
A line item MAY offer entries in several currencies. A commitment is in
exactly one: the committed entry's `currency`. `commitment.currency`, when
present, MUST equal it, and `min_spend`, the `commitment_bounds` budgets,
and § 3.1 `delta_flat` are read in it. OpenProposal never converts.
§ 5.6.1, add: `pricing_id`, REQUIRED when `pricing[]` has more than one entry.
After § 5.6.2, add an unnumbered subsection:
#### Cost methods
An IAB-maintained vocabulary, versioned apart from the schema; adding a
term needs no schema change. Bare names belong to it and compare
case-insensitively, so `flat` is `FLAT`:
| `cost_method` | One unit | Rate per | `cost_parameters` |
| :--- | :--- | :--- | :--- |
| `CPM` | impression | 1,000 | |
| `CPMV` | viewable impression | 1,000 | `viewability_standard` |
| `CPC` | click | 1 | |
| `CPCV` | completed view | 1 | |
| `CPV` | view | 1 | `view_threshold` |
| `CPP` | rating point | 1 | `demographic`, `rating_source` |
| `CPA` | action | 1 | `event`, `attribution_window`, `event_source` |
| `PLAY` | DOOH play on one screen or one sync group | 1,000 | |
| `TIME` | `time_unit` | 1 | `time_unit`: `hour` \| `day` \| `week` |
| `FLAT` | line item | | |
Anyone MAY define an extension term. Its prefix is a domain the definer
controls, such as `example-ssp.com:cpa_guaranteed`; a seller's own terms
MUST use its `seller_domain`. The `cost_definition` URL's host MUST be
the prefix domain or a subdomain of it. A term's meaning MUST NOT change once
published; a changed meaning takes a new name.
When `basis` is `spend`, `amount` is the seller total, on the same
terms as `agreed_rate`, including selected `delta_flat` charges
(§ 3.1), which MUST NOT exceed it. `FLAT` commits on `spend`.
For other entries, `derived_units` = (`amount` − those charges) ÷
`agreed_rate` × rate per, rounded down to a whole unit; `TIME` units are `time_unit`s from
`flight_start` through `flight_end`, inclusive. When `basis` is `units`, the seller total is `amount` ÷ rate
per × `agreed_rate` plus those charges; `min_spend` and
`commitment_bounds` budgets apply to it. A seller fee is never a
`pricing[]` entry. A consumer MUST treat an entry with an unrecognized
`cost_method`, or an extension entry that breaks these rules, as
unavailable, not the line item as invalid.
§ 3.1: `delta_cpm` adjusts only `CPM` and `CPMV` entries; an option
priced only by `delta_cpm` MUST NOT resolve against any other entry.Why
We ask two separable things: a vocabulary for cost_method, and a meaning for several pricing[] entries. Either can be adopted alone.
cost_method is the billable unit, with no list and no meaning. § 5.6 ends the Enum with "etc.", and § 5.6.1 derives units from it by an unstated divisor. Views, rating points, and actions also need counting parameters.
A closed core list alone fails: a new model, such as the outcome-based pricing #80 asks for, waits for registration, and a proprietary one never gets in. Sellers write flat plus prose instead, as #45 does. Free strings fail the other way: CPCV and cost_per_completed_view never match.
A domain prefix can't collide, and it names who answers for the term, as <seller_namespace> does in § 2.2. With cost_definition on that domain, a reader checks a term's definer as it checks a seller (#61). Inline rate_per and unit keep the record self-contained. CPM, CPMV, CPC, daily TIME, and FLAT map to OpenDirect 2.1 ratetype; Ad Manager cost types add CPCV.
Nothing says what two pricing[] entries mean: a choice, a per-currency copy, or charges that add up. The comment template names the gap: "pricing[] sits above transaction_mechanism." A § 3.1 delta on transaction_mechanism changes only the rate, not the floor or unit. We ask: alternatives with an id, chosen once in commitment, which takes that entry's currency.
A spend amount includes selected delta_flat fees, as @aleksUIX's fee-basis PR (#117) proposes, and derived_units counts only the rest. Otherwise a fee overruns amount or goes unpaid.
Details: Pricing models and price alternatives: full rationale and examples
Knock-on effects
- § 2.1: the summary lists each entry's
pricing_id,cost_method,gross_rate, andcurrency. - Our reply on #30 locates an entry by
cost_method;pricing_idreplaces that. #63's record carriescommitment.pricing_id. commitment_boundsimpressions count the committed entry's units;min_spendand thecommitment_boundsbudgets apply to the seller total, selecteddelta_flatcharges included.- @dineshbhat's
commitment.amountchange request (#115) makes a seller fee its ownpricing[]entry. Entries here are alternatives, so a fee there would be another choice, not a charge. - Whether
agreed_rateis gross or net of agency commission stays open in our floor and rate-basis reply on #30, open question 3, and tax in thebilling.tax_inclusiveflag that #115 proposes.amountuses the same terms asagreed_rate, so the rule holds either way. - § 1.1 carriers take five OpenDirect rate types and deals take CPM; the controlling counter bills other terms.
- #82 asks what a DOOH CPM counts; our DOOH plays filing answers it with
impression_multiplier. - Breaking:
commitment.pricing_idis REQUIRED with several entries;delta_cpmoptions, § 5.3 audiences included, resolve only againstCPMandCPMVentries.flatstays valid.
Open questions for the working group
- Entries with different
cost_methods share onecommitment_bounds, so shouldmin_impressionsandmax_impressionscount the committed entry's units, as we propose, be renamedmin_unitsandmax_units, move into each entry, or give way to budget-only bounds? - Should § 3.1 Selectable structure
delta_cpmadjust onlyCPMandCPMVentries, as we propose, or read as an adjustment per rate unit on every entry? - Should § 5.3 Audience reach
audiencesacceptdelta_pctanddelta_flat, so that audience options can price non-CPM entries, or should audience options resolve only againstCPMandCPMVentries? - Should a programmatic guaranteed or private auction entry in a term that the § 1.1 Downstream standards deal carriers can't express, such as
CPCV, be allowed and billed outside the deal carrier on the controlling count, as we propose, discouraged with a SHOULD NOT, or forbidden? - Should the buyer name its entry in
commitment.pricing_id, as we propose, or shouldpricingbecome a § 3.1 Selectable structure selectable field that the buyer sets through theselected[]key proposed in the buyer's selection key (#22)?
Would this break an implementation already built to this draft?
Yes — breaking
Alternatives you considered and rejected
- A closed registry, as #62 uses for schemes. The closed list's delay; we keep its unknown-token rule.
- AdCOM 1.0's "vendor-specific codes typically starting at 500". Two vendors can pick the same code.
- Prefix core terms too (
iab:CPM). Breaks every example. - One price per line item. Duplicate line items over one inventory; § 2 subsetting lets a buyer commit both.
- Revenue share. A commission on attributed sales, not a rate on a unit (gist).
You are commenting as
Other — IAB Tech Lab member (Postindustria).
Before you submit
- I have read CONTRIBUTING.md and agree my contribution may be published under this repository's licence.
- This contains no confidential or commercially sensitive information.
Revised 2026-10-27: A PLAY unit is one play on a screen or sync group, following @premesh, and derived_units rounds down to a whole unit, following @EvgenyAndroid.
Analyzed and generated with the help of Claude, fully reviewed by me.
Activity
KonstantinMirin commentedon Oct 25, 2026
Revision, from @aleksUIX's fee-basis PR (#117), on @dineshbhat's
commitment.amountchange request (#115). Ourderived_unitssentence reads all of a spendamountas media, so a selecteddelta_flatfee overrunsamountor goes unpaid. We replace that whole sentence with:Gross or net of agency commission stays open in our floor and rate-basis reply on #30, open question 3, and tax in the
billing.tax_inclusiveflag that #115 proposes.amountuses the same terms asagreed_rate, so the formula holds either way.Analyzed and generated with the help of Claude, fully reviewed by me.
EvgenyAndroid commentedon Oct 27, 2026
Implementation evidence for the "entries are alternatives" rule and
pricing_id. Without them I can only execute a line item with exactly onepricing[]entry. With two, nothing tells me whether they combine or which one the buyer accepted, and aselectableoption's price delta can't say which entry it modifies.One gap this and #103 don't close yet: rounding. The display example gives
derived_units: 3333333for 80,000.00 at a 24.00 CPM, which truncates 3,333,333.33. "Informative, not binding" is fine, but two implementations should still get the same number. A stated rule (truncate, or round half-even) would make it reproducible.