Skip to content

[Change] § 5.6, § 1.1, § 2.1 — Say which price a deal carries: agreed_rate as the Deals API dealfloor, with its pricetype; rename floor to min_rate #133

Open

Description

@KonstantinMirin

What kind of change?

Add a new field

Which section?

5.6 — Commercial terms

Current text

§ 5.6:

| `pricing[].gross_rate` | Number | seller-set | The list rate the buyer pays |
| `pricing[].agreed_rate` | Number | derived | The transacted rate after selections and any agreed request |
| `pricing[].currency` | String | seller-set | ISO-4217 |
| `pricing[].floor` | Number | seller-set | OPTIONAL. The lowest rate the seller will consider. Enables a `requestable` counter to be evaluated without a round trip |

§ 2.1, Summary Representation, per line item:

`pricing.cost_method` · `pricing.gross_rate` ·

Proposed text

§ 5.6, replace the `pricing[].floor` row, as amended by PR #18 if it merges, with these two rows:

| `pricing[].min_rate` | Number | seller-set | OPTIONAL. The lowest rate the seller will accept for the line item. Enables a `requestable` counter to be evaluated without a round trip. Not the downstream auction floor, and never sent downstream |
| `pricing[].floor` | Number | seller-set | Deprecated and reserved. Holds the same value as `min_rate`. Removed in 4.0 |

§ 5.6, after the `pricing[].currency` row:

| `pricing[].pricetype` | Integer | seller-set | REQUIRED when the line item offers `PROGRAMMATIC_GUARANTEED`, `PREFERRED_DEAL` or `PRIVATE_AUCTION`. How `agreed_rate` clears, as Deals API 1.0 `terms.pricetype`: Dynamic (0), the auction type of each bid request; First Price (1); Second Price Plus (2); Fixed Price (3); or an exchange-specific value of 500 or greater |

§ 5.6, after the table:

**Deal price.** For a deal, the committed entry's `agreed_rate` is the deal's
price per thousand impressions, in that entry's `currency`. Under Fixed Price
(3), it is the price the buyer pays. Under an auction `pricetype`, it is the
deal's minimum bid. The Deals API treats it as guidance: per-impression floors
can be higher, so a bid at `agreed_rate` is not guaranteed to clear.
`min_rate` belongs to negotiation and is never sent downstream.

**Migration.** Until 4.0, sellers and buyers write both `min_rate` and
`floor`, with the same value. A `pricing[]` entry whose old and new values
differ is invalid. 4.0 removes `floor`, and its name stays reserved: no later
version reuses it.

§ 1.1, add rows to the Deals API handoff table:

| Deals API 1.0 | OpenRTB 2.6 | From the agreed line item |
| :--- | :--- | :--- |
| `terms.dealfloor` | `Deal.bidfloor` | `agreed_rate` of the committed `pricing[]` entry |
| `terms.cur` | `Deal.bidfloorcur` | That entry's `currency`, always sent |
| `terms.pricetype` | `Deal.at`, the same value, omitted for Dynamic (0) | That entry's `pricetype`, always sent |
| `terms.guar` | `Deal.guar` | `1` when the selected mechanism is `PROGRAMMATIC_GUARANTEED`, `0` otherwise |
| `terms.units` | | `commitment.amount` when `basis` is `units`, otherwise `derived_units` |
| `terms.totalcost` | | `commitment.amount` when `basis` is `spend`, otherwise `amount` × `agreed_rate` ÷ 1,000, plus any selected `delta_flat` charges |

§ 2.1, Summary Representation, per line item: add `pricing.pricetype` after
`pricing.gross_rate`.

Why

For a deal, the draft never says which of its four rates goes downstream. We ask it to say: agreed_rate, with a pricetype that says whether it's a fixed price or a minimum bid, as the Deals API does.

The Deals API 1.0 Terms carries one price, dealfloor: "Minimum bid … Unless pricetype is Fixed, this should be used as guidance". pricetype says which. OpenRTB 2.6 Deal pairs bidfloor with at the same way: under at 3, bidfloor "is the agreed upon deal price". Both are CPM.

@fgranata (#19) and @VJAlkimi (#30) already read the mapping this way: the Deals API line carries the agreed rate. The text doesn't say so, and a mapper that matches names sends floor. In the display example, that sends 21.00 for a 24.00 guaranteed deal. In the CTV example, a private auction, the deal floor becomes the 39.60 offer floor, not the derived 45.00. @Sirajmx's PR #18 clarifies that floor is "not the downstream auction floor". This request names the field that is. It also renames floor to min_rate, to match the other rates and stay clear of bidfloor and dealfloor.

transaction_mechanism doesn't give a private auction's auction type, which the Deals API needs. An absent pricetype defaults to Second Price Plus (2), while Dynamic (0) defers to the bid request. OpenProposal states pricetype for every deal, so the default never applies. The name and values are the Deals API's, including its extension range from 500, so no new list is needed. The Deal price paragraph covers @fgranata's scenario in #16: bids at the agreed price lose to a higher exchange floor.

guar, units, and totalcost follow from fields OpenProposal has. Our delivery type change request (#93) maps PROGRAMMATIC_GUARANTEED to a reserved delivery type and the other deal mechanisms to non_guaranteed.

flowchart LR
    G["gross_rate"] -->|"selections, counter at or above min_rate"| A["agreed_rate"]
    F["min_rate"] -.->|"negotiation only, never sent"| A
    A -->|"with pricetype and currency"| D["Deals API terms.dealfloor"]
    D --> B["OpenRTB 2.6 Deal.bidfloor"]
Loading

Details: Deals API alignment: full crosswalk

Knock-on effects

  • The rename is not breaking in 3.x: floor stays, deprecated, until 4.0 removes it.
  • The handoff table is in our deal handoff change request.
  • "The committed entry" is the entry that commitment.pricing_id names in our cost-method change request (#94). pricetype joins the keys a pricing_id is never reused for.
  • pricetype is an offered term, inside the binding record of our binding-record change request (#63).
  • derived_units is informative, so on a spend basis terms.units is an estimate.
  • totalcost depends on what commitment.amount includes, which @dineshbhat's #115 asks.
  • Appendix A and B: pricetype and min_rate join seller-set, and floor is marked deprecated. The examples add min_rate beside floor, and a pricetype: Fixed Price (3) for display, an auction type for CTV.

Open questions for the working group

  1. A line item that offers PREFERRED_DEAL and PRIVATE_AUCTION may need two price types. Should each pricing[] entry name the mechanisms it prices, with the transaction_mechanisms[] of our cost-method change request (#94)? Or should a line item's deal mechanisms share one pricetype?
  2. dealfloor and bidfloor are CPM. Should a deal require a CPM entry, or may a flat-priced programmatic guaranteed deal send only totalcost and units? Our cost-method change request (#94) lists the other cost methods.
  3. Should PROGRAMMATIC_GUARANTEED require Fixed Price (3)? The Deals API says a price "must be provided if the deal is a fixed price deal, especially if it's a programmatic guaranteed deal", but it doesn't require the pairing.
  4. Is min_rate the right name for the field that replaces pricing[].floor (§ 5.6), or another, such as offer_floor? We leave the final spelling to the working group. PR #18 clarifies the meaning either way.

Would this break an implementation already built to this draft?

Yes — breaking

Alternatives you considered and rejected

  • Map min_rate to dealfloor. It sends the seller's offer floor, below the agreed price.
  • Derive pricetype from transaction_mechanism. A private auction can run first price, second price, or dynamic, so the mechanism doesn't say which.
  • String values, such as first_price. The Deals API and OpenRTB use the integers, and the 500 range needs no registry. Our placement PR (#120) carries AdCOM integer codes the same way.
  • Rename floor without a deprecation. It breaks implementations built to 3.0.

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.

Analyzed and generated with the help of Claude, fully reviewed by me.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions