Linear TV Buying Guide¶
The buyer agent supports linear television inventory through the same quote-then-book flow used for digital deals. Linear TV buying introduces scatter market purchasing, DMA-level geographic targeting, and traditional TV pricing models (CPP and CPM) — all accessible through the standard DealsClient with media_type: "linear_tv".
New in v1.1
Linear TV buying support shipped in Phase 1. The functionality described here is available now.
Overview¶
Linear TV buying follows a scatter market model: the buyer requests pricing for specific dayparts, networks, and DMAs, receives a non-binding quote, and books confirmed spots. This mirrors the digital quote-then-book flow but adapts to television's unique inventory structure — fixed airtime slots, geographic markets, and audience-based pricing.
sequenceDiagram
participant Buyer as Buyer Agent
participant Client as DealsClient
participant Seller as Seller Agent
Buyer->>Client: Request linear TV quote
Client->>Seller: POST /api/v1/quotes (media_type: "linear_tv")
Seller-->>Client: QuoteResponse (CPP/CPM pricing, DMA avails)
Buyer->>Client: Book the spot
Client->>Seller: POST /api/v1/deals
Seller-->>Client: DealResponse (confirmed airtime, spot details)
Scatter Market Buying¶
Scatter buying is the purchase of TV inventory outside the upfront commitment window — typically for the current or next quarter. The buyer agent targets scatter because it maps naturally to the quote-then-book flow: inventory is priced on demand, availability changes frequently, and deals are booked individually rather than as part of a long-term commitment.
Requesting a Linear TV Quote¶
Use the standard DealsClient.request_quote() with media_type set to "linear_tv" and linear-specific fields in the request:
from ad_buyer.clients.deals_client import DealsClient
from ad_buyer.models.deals import QuoteRequest, BuyerIdentityPayload
from ad_buyer.models.linear_tv import LinearTVParams
async with DealsClient(seller_url, api_key="key") as client:
quote = await client.request_quote(QuoteRequest(
product_id="prod-linear-primetime-001",
media_type="linear_tv",
deal_type="PD",
impressions=2_000_000,
flight_start="2026-07-01",
flight_end="2026-09-30",
target_cpm=12.00,
linear_tv=LinearTVParams(
target_demo="A25-54", # required
dayparts=["primetime"],
networks=["NBC", "CBS", "ABC"],
dmas=["501", "803"], # NYC, LA
spot_length=30,
),
buyer_identity=BuyerIdentityPayload(
seat_id="ttd-seat-123",
agency_id="omnicom-456",
),
))
print(f"Quote ID: {quote.quote_id}")
print(f"CPM: ${quote.pricing.final_cpm}")
if quote.pricing.final_cpp is not None:
print(f"CPP: ${quote.pricing.final_cpp}")
Linear TV Quote Parameters (LinearTVParams)¶
| Parameter | Type | Description |
|---|---|---|
target_demo |
str (required) |
Demographic target (e.g., "A25-54", "A18-49", "HH", "P2+") |
grps_requested |
int \| None |
Requested volume in Gross Rating Points (alternative to impressions) |
dayparts |
list[str] \| None |
Time slots: "primetime", "daytime", "early_morning", "late_night", "early_fringe", "prime_access", "overnight", "weekend" |
networks |
list[str] \| None |
Target network call signs (e.g., ["NBC", "CBS"]) |
dmas |
list[str] \| None |
Nielsen DMA codes for local buying; None means national |
spot_length |
int (default 30) |
Spot duration in seconds: 15, 30, or 60 |
target_cpp |
float \| None |
Desired Cost Per Point |
DMA-Level Targeting¶
Linear TV inventory is geographically structured around Nielsen Designated Market Areas (DMAs). The buyer can target specific DMAs or request national coverage.
Common DMA Codes¶
| DMA Code | Market |
|---|---|
501 |
New York |
803 |
Los Angeles |
602 |
Chicago |
504 |
Philadelphia |
506 |
Boston |
807 |
San Francisco-Oakland-San Jose |
623 |
Dallas-Fort Worth |
511 |
Washington, DC |
524 |
Atlanta |
753 |
Phoenix |
National vs. Local Buys¶
# National buy — no DMA filtering
national_quote = await client.request_quote(QuoteRequest(
product_id="prod-linear-primetime-001",
media_type="linear_tv",
linear_tv=LinearTVParams(
target_demo="A25-54",
dayparts=["primetime"],
networks=["NBC"],
spot_length=30,
# No dmas = national coverage
),
))
# Local buy — specific DMAs
local_quote = await client.request_quote(QuoteRequest(
product_id="prod-linear-local-001",
media_type="linear_tv",
linear_tv=LinearTVParams(
target_demo="A18-49",
dayparts=["primetime"],
dmas=["501", "803", "602"], # NYC, LA, Chicago
spot_length=30,
),
))
Pricing Models¶
Linear TV supports two pricing models. The seller's quote response indicates which model applies.
CPM (Cost Per Mille)¶
Standard cost-per-thousand-impressions pricing. This is the same model used for digital inventory and is the default for linear TV quotes.
CPP (Cost Per Point)¶
Cost per rating point — a traditional TV metric where one "point" equals 1% of the target demographic universe in a given DMA. CPP pricing appears in the quote response alongside CPM when the seller supports it.
quote = await client.request_quote(quote_request)
# CPM pricing (may be None for pricing_type=on_request)
print(f"Pricing model: {quote.pricing.pricing_model}") # "cpm", "cpp", "unit_rate", or "hybrid"
print(f"CPM: ${quote.pricing.final_cpm}")
# CPP appears on the pricing block for linear TV quotes
if quote.pricing.final_cpp is not None:
print(f"CPP: ${quote.pricing.final_cpp}")
# Rich linear TV details are nested under quote.linear_tv (LinearTVQuoteDetails)
if quote.linear_tv is not None:
print(f"Estimated GRPs: {quote.linear_tv.estimated_grps}")
print(f"Seller CPP: ${quote.linear_tv.cpp}")
print(f"Spots/week: {quote.linear_tv.spots_per_week}")
| Metric | Definition | When to Use |
|---|---|---|
| CPM | Cost per 1,000 impressions | Cross-media comparison, digital-first buyers |
| CPP | Cost per rating point (1% of demo universe) | Traditional TV planning, reach/frequency optimization |
Booking Linear TV Deals¶
Once you have a quote, booking works identically to digital deals:
from ad_buyer.models.deals import DealBookingRequest
deal = await client.book_deal(DealBookingRequest(
quote_id=quote.quote_id,
buyer_identity=BuyerIdentityPayload(seat_id="ttd-seat-123"),
notes="Q3 primetime scatter buy — NYC and LA",
))
print(f"Deal ID: {deal.deal_id}")
print(f"Status: {deal.status}")
print(f"CPM: ${deal.pricing.final_cpm}")
The seller confirms the spot allocation and returns a deal with airtime details. The deal flows through the same lifecycle statuses as digital deals: proposed -> active -> completed.
TIP Standard Compatibility¶
The linear TV implementation is designed for compatibility with the TIP (Television Interface Practices) standard. TIP defines the electronic data interchange formats used by TV buyers and sellers for order management, invoicing, and reconciliation. While the buyer agent communicates via the IAB quote-then-book API, the underlying data model aligns with TIP concepts:
- Spot — Individual ad placement within a program or daypart
- Unit — A confirmed spot with airtime details
- Avails — Available inventory communicated via the quote response
This alignment means linear TV deals booked through the buyer agent can integrate with TIP-compliant trafficking and billing systems downstream.
How It Works: Hybrid Media Type Handling¶
Linear TV is treated as a special case of the standard deal flow rather than a separate system. The core quote-then-book flow (quotes, negotiation, booking) remains media-type-agnostic, while media-type-specific parameters are passed through the linear_tv extension field. This means:
- The
DealsClientAPI is the same regardless of media type - Linear TV-specific validation (daypart values, DMA codes, spot lengths) is applied contextually when
media_typeis"linear_tv" - Digital and linear TV deals coexist in the same
DealStore - The negotiation client works unchanged — price negotiation is price negotiation regardless of medium
This hybrid design avoids forking the codebase for each media type while still supporting the unique attributes of linear television.
Related¶
- Deals API — Quote-then-book flow and
DealsClientreference - Negotiation — Price negotiation works identically for linear TV deals
- Multi-Seller Discovery — Discover sellers with linear TV inventory
- Seller Agent Docs — Seller-side API reference