OpenRTB protocol
Bid floors in OpenRTB: bidfloor and bidfloorcur
imp.bidfloor is the minimum bid for an impression, expressed as CPM, a float defaulting to 0. imp.bidfloorcur names its currency as an ISO-4217 alpha code, defaulting to "USD". The floor is per impression, not per request, and deals can override it again per buyer.
The two fields and their defaults
{
"id": "1",
"video": { "mimes": ["video/mp4"], "plcmt": 1 },
"bidfloor": 4.50,
"bidfloorcur": "EUR"
}Per the 2.6 spec, bidfloorcur "sets the default for all floors specified in the Imp object", which matters once duration floors enter the picture below. Because both fields default, an impression with no floor at all is legal and common. Each imp in the bid request carries its own floor, so multi-impression requests can price a masthead and a footer slot differently.
Currency: cur vs bidfloorcur
The request-level cur array lists the currencies the exchange accepts bids in. bidfloorcur is independent of it: an exchange may floor in EUR while accepting bids only in USD. When they differ, the bidder converts the floor into its bidding currency before comparing, using rates agreed with the exchange or a common reference. Bidding 5.00 USD against a 4.50 EUR floor is below floor on most days, and the bid is filtered.
Per-deal floors in pmp.deals
Private marketplace deals live in imp.pmp.deals, an array of Deal objects. Each deal carries its own bidfloor (default 0) and bidfloorcur (default USD). Note the spec's explicit warning: Deal.bidfloorcur does not inherit from imp.bidfloorcur. A EUR floor on the impression plus a bare floor on the deal means the deal floor is in USD.
Deal.at can override the auction type per deal: 1 = first price, 2 = second price plus, and 3 = the value in bidfloor is the agreed fixed deal price. With at = 3 the floor stops being a floor and becomes the transaction price. wseat and wadomain restrict who may bid on the deal (buyer seats and advertiser domains respectively; omission means no restriction), and pmp.private_auction = 1 restricts the whole impression to the listed deals.
Duration floors (2.6)
For video and audio pods, price scales with duration. OpenRTB 2.6 added durfloors, an array of DurFloors objects available at imp.video.durfloors, imp.audio.durfloors, and Deal.durfloors. Each entry has mindur, maxdur (at least one is required, and a missing end is unbounded), and a bidfloor in CPM. A creative whose duration falls outside every defined range falls back to the Imp-level bidfloor. The related mincpmpersec field floors dynamic pod pricing per second instead. Both are covered in context on the CTV and ad pods page, and the full 2.6 delta is in OpenRTB 2.5 vs 2.6.
One adjacent thing that is not part of the protocol: Prebid's Price Floors module computes and enforces floors inside the wrapper, a layer above the OpenRTB fields described here.
FAQ
What happens if a bid is below the floor?
The exchange filters it out of the auction. If the exchange supports loss notices, the bidder's lurl may fire with loss reason 100 (Bid was Below Auction Floor) or 101 (Bid was Below Deal Floor) substituted into the AUCTION_LOSS macro. Nothing in the protocol prevents bidding below floor; it is simply a wasted bid.
Is bidfloor required?
No. imp.bidfloor is optional and defaults to 0, meaning no floor. bidfloorcur defaults to USD. An absent floor and an explicit 0 floor mean the same thing: any positive bid price is acceptable.
Is the floor per request or per impression?
Per impression. bidfloor sits on each Imp object, so a request with three impressions can carry three different floors, and each Deal inside imp.pmp can override the floor again for buyers on that deal.
Validate it
Floors fail in boring ways: bidfloor sent as a string, a lowercase "usd", durfloors misplaced on imp instead of imp.video. Paste your request into the bid request tester: rtblint checks types and flags fields the spec does not define at that path via openrtb.field.undefined. The CLI does the same in pipelines.