Deal IDs & Private Marketplace (PMP)#
Ever notice how the ads on The New York Times or Wall Street Journal never seem to be for sketchy weight-loss pills or “one weird trick” scams? That’s Private Marketplace deals at work—the VIP lounge of programmatic advertising where publishers get to pick who shows up to the party.
Unlike the open exchange (which is basically the digital equivalent of selling ad space on Craigslist), PMP lets premium publishers say “you, you, and you can bid—but the rest of you tech bros, not today.”
What’s a Private Marketplace, Really?#
Think of it like Costco, but for ads. You need a membership to get in, and once you’re inside, you get access to the good stuff at prices that were negotiated upfront. No surprise $47 CPMs at 2 AM.
Publishers love PMPs because they:
Control who sees their inventory (no sketchy advertisers next to their Pulitzer-winning journalism)
Lock in better prices ($5-$20 CPMs vs the $0.50-$2 wasteland of open exchanges)
Guarantee brand safety (Nike doesn’t want to appear next to conspiracy theories or adult content)
Build actual relationships with advertisers instead of treating everyone like a random bidder on eBay
PMP vs Open Exchange (The Difference)#
Feature |
Open Exchange |
Private Marketplace |
|---|---|---|
Access |
Anyone with a credit card |
Invitation only |
Pricing |
Whatever chaos dictates |
Pre-negotiated |
Inventory |
The leftover pizza |
The good stuff |
Transparency |
“Trust us” |
Actual contracts |
Brand Safety |
Roll the dice |
Guaranteed |
Floor Price |
$0.50-$2 (yikes) |
$5-$20+ (worth it) |
Three Flavors of PMP Deals#
1. Preferred Deals (First Dibs, No Promises)#
This is like being first in line at a yard sale. You get to see the inventory before it goes to auction, at a fixed price. But if you don’t want it? No problem—publisher moves on to the next buyer.
preferred_deal = {
"deal_id": "PREF-12345",
"deal_type": "preferred",
"publisher": "Premium News Publisher",
"buyer_seat_id": "DSP-BRAND-001",
"price": 8.50, # Fixed CPM - take it or leave it
"currency": "USD",
"guaranteed": False, # Not guaranteed to fill
"priority": 1, # You get first look
"inventory": {
"site": "premium-news.com",
"sections": ["/business", "/technology"],
"ad_sizes": ["728x90", "300x250", "970x250"],
"position": "above_fold" # The primo real estate
},
"terms": {
"start_date": "2025-01-01",
"end_date": "2025-12-31",
"viewability_guarantee": 70, # 70% of impressions must be viewable
"brand_safety": True
}
}
2. Programmatic Guaranteed (Reserved Seats)#
This is the airline’s first-class section—you paid for it, you’re getting it. Publisher guarantees you a specific number of impressions at a fixed price. Like a traditional insertion order (IO) but without the endless email chains and PDF attachments.
programmatic_guaranteed = {
"deal_id": "PG-67890",
"deal_type": "programmatic_guaranteed",
"publisher": "Premium Lifestyle Magazine",
"buyer_seat_id": "AGENCY-ATD-001",
"price": 12.00, # Premium inventory = premium price
"currency": "USD",
"guaranteed": True, # You WILL get these impressions
"guaranteed_impressions": 1000000, # 1M impressions or bust
"daily_cap": 50000,
"inventory": {
"site": "lifestyle-magazine.com",
"sections": ["/homepage"],
"ad_sizes": ["970x250"], # Homepage takeover
"format": "display"
},
"terms": {
"start_date": "2025-06-01",
"end_date": "2025-08-31",
"billing": "CPM",
"makegoods": True, # If they underdeliver, they comp you
"cancellation_notice": "30_days"
},
"delivered_impressions": 0 # Track actual delivery
}
3. Private Auction (Closed Bidding War)#
Multiple invited buyers compete, but it’s not a free-for-all. Publisher sets a floor price and only lets in the brands they trust. Think silent auction at a charity gala, not a mob scene at a Black Friday sale.
private_auction = {
"deal_id": "PA-11223",
"deal_type": "private_auction",
"publisher": "Sports Network",
"invited_buyers": [
"DSP-001", # Only these four get to bid
"DSP-002",
"DSP-003",
"DSP-004"
],
"floor_price": 5.00, # Don't even think about bidding lower
"currency": "USD",
"auction_type": "second_price", # Winner pays second-highest bid
"inventory": {
"site": "sports-network.com",
"categories": ["sports", "fitness"],
"ad_sizes": ["300x600", "300x250"],
"device_types": ["desktop", "mobile"]
},
"terms": {
"start_date": "2025-03-01",
"end_date": "2025-05-31",
"viewability_guarantee": 65
}
}
How Deal IDs Travel (The Technical Bit)#
Deal IDs live inside the bid request in a pmp object. It’s like a secret handshake—if you’ve got the right deal ID, you get access to the premium inventory. No deal ID? Enjoy the open auction with everyone else.
Here’s what it looks like in OpenRTB 2.5:
# Bid request with PMP deal
bid_request_with_pmp = {
"id": "abc123",
"imp": [{
"id": "1",
"banner": {
"w": 728,
"h": 90,
"pos": 1 # Above the fold = more expensive
},
"pmp": {
"private_auction": 1, # 1 = deals only, no open auction fallback
"deals": [
{
"id": "PREF-12345", # The magic ticket
"bidfloor": 8.50, # Minimum bid for this deal
"bidfloorcur": "USD",
"at": 2, # 1=first price, 2=second price
"wseat": ["DSP-BRAND-001"], # Who's allowed to bid
"wadomain": ["brand.com"], # Advertiser whitelist
"ext": {
"priority": 1,
"deal_type": "preferred"
}
}
]
},
"bidfloor": 2.00, # Open auction floor (way cheaper)
"bidfloorcur": "USD"
}],
"site": {
"id": "site123",
"name": "Premium News Publisher",
"domain": "premium-news.com",
"cat": ["IAB12"] # News category
},
"user": {
"id": "user456"
},
"device": {
"ua": "Mozilla/5.0...",
"ip": "192.168.1.1"
}
}
Managing PMP Deals (The Code)#
Here’s how to match deals to buyers and track which ones are eligible:
from datetime import datetime
class PMPDealManager:
"""Manage your PMP deals without losing your mind"""
def __init__(self):
self.deals = []
def add_deal(self, deal):
"""Add a new deal to the system"""
# Basic validation - don't skip this or you'll regret it later
required_fields = ['deal_id', 'deal_type', 'price', 'buyer_seat_id']
for field in required_fields:
if field not in deal:
raise ValueError(f"Missing required field: {field}")
self.deals.append(deal)
print(f"Added deal: {deal['deal_id']}")
def find_eligible_deals(self, bid_request, buyer_seat_id):
"""
Find which deals this buyer can actually access
Returns the good stuff first (guaranteed > preferred > private auction)
"""
eligible = []
imp = bid_request['imp'][0]
site = bid_request.get('site', {})
for deal in self.deals:
# Active date range check
if not self._is_active(deal):
continue
# Is this buyer even invited?
if not self._is_buyer_eligible(deal, buyer_seat_id):
continue
# Does the inventory match what they're looking for?
if not self._matches_inventory(deal, imp, site):
continue
# For guaranteed deals, check if we still have capacity
if deal['deal_type'] == 'programmatic_guaranteed':
if not self._has_capacity(deal):
continue
eligible.append(deal)
# Sort by what matters: guaranteed first, then by price
eligible.sort(key=lambda d: (
d['deal_type'] == 'programmatic_guaranteed',
d.get('priority', 99),
-d['price']
))
return eligible
def _is_active(self, deal):
"""Check if deal is still valid (not expired)"""
if 'terms' not in deal:
return True
terms = deal['terms']
now = datetime.now()
start = datetime.fromisoformat(terms.get('start_date', '2020-01-01'))
end = datetime.fromisoformat(terms.get('end_date', '2099-12-31'))
return start <= now <= end
def _is_buyer_eligible(self, deal, buyer_seat_id):
"""Check if this buyer is on the list"""
if deal['deal_type'] == 'private_auction':
return buyer_seat_id in deal.get('invited_buyers', [])
else:
return deal.get('buyer_seat_id') == buyer_seat_id
def _matches_inventory(self, deal, imp, site):
"""Check if the ad size and site match the deal terms"""
inventory = deal.get('inventory', {})
# Site domain must match
if 'site' in inventory:
if site.get('domain') != inventory['site']:
return False
# Ad size must match
if 'banner' in imp and 'ad_sizes' in inventory:
size = f"{imp['banner']['w']}x{imp['banner']['h']}"
if size not in inventory['ad_sizes']:
return False
return True
def _has_capacity(self, deal):
"""Check if guaranteed deal hasn't hit its cap yet"""
if 'guaranteed_impressions' not in deal:
return True
delivered = deal.get('delivered_impressions', 0)
total = deal['guaranteed_impressions']
return delivered < total
def record_win(self, deal_id):
"""Track impression delivery (important for guaranteed deals)"""
for deal in self.deals:
if deal['deal_id'] == deal_id:
if 'delivered_impressions' not in deal:
deal['delivered_impressions'] = 0
deal['delivered_impressions'] += 1
return True
return False
# Usage example
pmp_manager = PMPDealManager()
# Add your deals
pmp_manager.add_deal(preferred_deal)
pmp_manager.add_deal(programmatic_guaranteed)
pmp_manager.add_deal(private_auction)
# Find what this buyer can access
eligible = pmp_manager.find_eligible_deals(
bid_request_with_pmp,
buyer_seat_id="DSP-BRAND-001"
)
print(f"\nFound {len(eligible)} eligible deals:")
for deal in eligible:
print(f" - {deal['deal_id']}: {deal['deal_type']} @ ${deal['price']} CPM")
DSP Bidding Logic (With Deals)#
DSPs prioritize deals over open auctions—better inventory, better performance, happier clients.
class DSPWithDeals:
"""DSP that knows how to play the PMP game"""
def __init__(self, seat_id, budget):
self.seat_id = seat_id
self.budget = budget
self.spent = 0.0
def create_bid(self, bid_request, eligible_deals):
"""
Bid on deals first, fall back to open auction if necessary
"""
imp = bid_request['imp'][0]
# Got deals? Use 'em
if eligible_deals:
return self._bid_on_deal(bid_request, eligible_deals[0])
# Check if open auction is even allowed
pmp = imp.get('pmp', {})
if pmp.get('private_auction') == 1:
# Nope, deals only
return None
return self._bid_open_auction(bid_request)
def _bid_on_deal(self, bid_request, deal):
"""Bid on a PMP deal at the agreed price"""
imp = bid_request['imp'][0]
bid_price = deal['price']
# Budget check (important!)
if self.spent + (bid_price / 1000) > self.budget:
return None
# Create bid response with the deal ID
return {
"id": bid_request['id'],
"seatbid": [{
"seat": self.seat_id,
"bid": [{
"id": f"bid_{deal['deal_id']}",
"impid": imp['id'],
"price": bid_price,
"dealid": deal['deal_id'], # Critical: include this
"adm": f"<div>Premium ad for {deal['deal_id']}</div>",
"crid": "creative_premium_001",
"w": imp['banner']['w'],
"h": imp['banner']['h']
}]
}],
"cur": "USD"
}
def _bid_open_auction(self, bid_request):
"""Fall back to open auction if no deals available"""
imp = bid_request['imp'][0]
floor = imp.get('bidfloor', 1.0)
bid_price = floor * 1.2 # Bid slightly above floor
if self.spent + (bid_price / 1000) > self.budget:
return None
return {
"id": bid_request['id'],
"seatbid": [{
"seat": self.seat_id,
"bid": [{
"id": "bid_open_001",
"impid": imp['id'],
"price": bid_price,
# No dealid for open auction
"adm": "<div>Standard ad</div>",
"crid": "creative_standard_001"
}]
}],
"cur": "USD"
}
# Example: Bid on available deals
dsp = DSPWithDeals(seat_id="DSP-BRAND-001", budget=10000.0)
eligible = pmp_manager.find_eligible_deals(
bid_request_with_pmp,
buyer_seat_id="DSP-BRAND-001"
)
bid_response = dsp.create_bid(bid_request_with_pmp, eligible)
if bid_response:
bid = bid_response['seatbid'][0]['bid'][0]
deal_id = bid.get('dealid', 'Open Auction')
print(f"\nBid created:")
print(f" Deal ID: {deal_id}")
print(f" Price: ${bid['price']} CPM")
Tracking Deal Performance#
You need to know if your PMP deals are actually worth the premium prices. Spoiler: they usually are, but you should verify.
class DealPerformanceTracker:
"""Track which deals are pulling their weight"""
def __init__(self):
self.stats = {}
def record_impression(self, deal_id, price):
"""Track impression delivery"""
if deal_id not in self.stats:
self.stats[deal_id] = {
"impressions": 0,
"clicks": 0,
"conversions": 0,
"spend": 0.0,
"revenue": 0.0
}
self.stats[deal_id]['impressions'] += 1
self.stats[deal_id]['spend'] += price / 1000
def record_click(self, deal_id):
"""Track clicks"""
if deal_id in self.stats:
self.stats[deal_id]['clicks'] += 1
def record_conversion(self, deal_id, revenue=0.0):
"""Track conversions and revenue"""
if deal_id in self.stats:
self.stats[deal_id]['conversions'] += 1
self.stats[deal_id]['revenue'] += revenue
def get_report(self):
"""Generate performance report (sorted by ROAS)"""
report = []
for deal_id, stats in self.stats.items():
impr = stats['impressions']
clicks = stats['clicks']
conv = stats['conversions']
spend = stats['spend']
revenue = stats['revenue']
ctr = (clicks / impr * 100) if impr > 0 else 0
cvr = (conv / clicks * 100) if clicks > 0 else 0
cpa = (spend / conv) if conv > 0 else 0
roas = (revenue / spend) if spend > 0 else 0
report.append({
"deal_id": deal_id,
"impressions": impr,
"clicks": clicks,
"conversions": conv,
"ctr": round(ctr, 2),
"cvr": round(cvr, 2),
"cpa": round(cpa, 2),
"spend": round(spend, 2),
"revenue": round(revenue, 2),
"roas": round(roas, 2)
})
# Best ROAS first
report.sort(key=lambda x: x['roas'], reverse=True)
return report
# Example: Compare deal performance vs open exchange
tracker = DealPerformanceTracker()
import random
# Simulate preferred deal traffic
for _ in range(1000):
tracker.record_impression("PREF-12345", price=8.50)
if random.random() < 0.025: # 2.5% CTR
tracker.record_click("PREF-12345")
if random.random() < 0.05: # 5% CVR
tracker.record_conversion("PREF-12345", revenue=30.0)
# Simulate programmatic guaranteed
for _ in range(500):
tracker.record_impression("PG-67890", price=12.00)
if random.random() < 0.032: # 3.2% CTR (better quality)
tracker.record_click("PG-67890")
if random.random() < 0.06: # 6% CVR
tracker.record_conversion("PG-67890", revenue=40.0)
# Simulate open exchange (for comparison)
for _ in range(2000):
tracker.record_impression("Open Exchange", price=2.50)
if random.random() < 0.015: # 1.5% CTR (worse quality)
tracker.record_click("Open Exchange")
if random.random() < 0.03: # 3% CVR
tracker.record_conversion("Open Exchange", revenue=20.0)
# See the results
print("\n=== Deal Performance Report ===")
report = tracker.get_report()
for r in report:
print(f"\n{r['deal_id']}:")
print(f" Impressions: {r['impressions']:,}")
print(f" CTR: {r['ctr']}%")
print(f" Conversions: {r['conversions']}")
print(f" CPA: ${r['cpa']}")
print(f" Spend: ${r['spend']:,.2f}")
print(f" Revenue: ${r['revenue']:,.2f}")
print(f" ROAS: {r['roas']}x")
The Bottom Line#
Private Marketplace deals are how premium publishers survive in programmatic advertising. Instead of racing to the bottom on price (looking at you, open exchanges), they lock in relationships with quality advertisers at fair prices.
Why PMPs matter:
Better inventory = better performance
Pre-negotiated prices = no surprise bills
Brand safety guarantees = sleep better at night
Direct relationships = actual humans you can call when things break
Three deal types to remember:
Preferred: First look, fixed price, non-guaranteed
Programmatic Guaranteed: Reserved inventory, contracted volume
Private Auction: Multiple invited buyers, competitive but controlled
Technical implementation:
Deal IDs travel in the
pmp.deals[]array in OpenRTBMatch deals to buyers using seat IDs
Always prioritize deals over open auction
Track performance by deal ID to prove ROI
In my experience working with both sides, PMPs are usually worth the premium. Higher CPMs, sure, but the quality difference is like comparing a Tesla to a ‘92 Civic—you get what you pay for.