A system design interview guide to building a real-time bidding system that, in the few dozen milliseconds it takes a page to load, asks many advertisers what they will pay for one ad slot, runs an auction, and serves the winning ad.
Student edition · start with the guarantee
Allocate ads under specified pricing, deadlines, and spend/exposure accounting.
Basic HTTP, databases, and programming are assumed. Specialized terms are explained below. Named products motivate the problem; this is an educational design, not a claim about their current internals. Capacity numbers are illustrative decimal payload estimates, not benchmarks. Add indexes, protocol overhead, replicas, headroom, and failure capacity before provisioning.
Real-time bidding is one of the most latency-sensitive systems you will ever be asked to design. Every time a user opens a page or app with an ad slot, an auction has to happen before that slot can be filled, and it has to finish fast enough that the user never notices. The system fans a single request out to many independent bidders, waits only as long as a strict budget allows, picks a winner, charges the right price, and serves the ad — typically inside a window of about a hundred milliseconds. The interesting engineering is not "show an ad," it is doing a distributed, money-moving auction under a hard deadline, at enormous request volume, while spending each advertiser's budget smoothly and never showing the same person the same ad too many times. This guide builds that design up from the moment a slot opens.
Each definition includes a concrete example and the condition under which the mechanism is useful. You can read this guide without opening another guide.
First-price, second-price, and GSP
A pricing rule connects bids to allocation and payment. First-price charges the winning bid. A textbook single-item second-price auction charges the highest competing bid, subject to a reserve and specified tie rule. Generalized second price handles ranked multiple slots.
Example. For single-item bids $5,$4,$2 with no reserve, first-price charges $5 and exact second-price charges $4. With equal-quality slots, GSP charges the next ranked bid per click.
Limit. Truthfulness of Vickrey auctions assumes independent private values and the textbook rule. GSP is not generally truthful. Quality weighting changes pricing; do not blindly charge the next raw bid.
Budget reservations and pacing
Pacing is a feedback policy that adjusts bidding toward a forecast spending curve. A hard budget instead requires accounting for both finalized spend and outstanding reservations before admitting more exposure.
Example. Budget $100, spent $90, outstanding reservations $8 leaves only $2 safely allocatable. Ten concurrent $1 wins cannot all rely on a stale '$10 left' read.
Limit. Delayed impression/click costs and refunds complicate reservations. A 95% cutoff is a heuristic, not a proof. Soft frequency caps and hard financial/legal limits need different contracts.
Token bucket
A counter of available tokens that refills at rate r up to capacity B. An admitted request spends its cost. The bucket permits an initial burst but bounds admissions over duration T by approximately B+rT.
Example. B=10, r=1 token/s admits 10 calls immediately, then about one per second. It can admit 70 calls over 60 seconds, so this is not a hard 60-calls-per-minute rule.
Limit. A distributed hard limit needs atomic, durable shared accounting or safely partitioned budgets. Clamp clock rollback, validate costs, and state whether rejected attempts consume tokens.
Deduplication
Recognizing multiple deliveries of one logical event using a stable identity. The same logical event must keep its ID across retries, and claiming the ID must be atomic with the counted or stored effect.
Example. Events e1,e2,e1 should yield a count of 2. An exact seen set plus the increment in one transaction makes the second e1 a no-op.
Limit. A TTL limits the dedup horizon; retries after expiry may count again. Approximate filters may drop new events, and changing the ID or routing a retry to another local seen set defeats dedup.
Backpressure and load shedding
Backpressure tells an upstream producer that the downstream stage cannot accept more work. Buffering delays that signal; shedding deliberately rejects or drops lower-priority work when a bound is reached.
Example. A sink accepts 100 events/s while input is 150/s. A 1000-event queue fills in 20 seconds. The system must then block, reject, or apply its documented drop policy.
Limit. A finite queue cannot absorb an infinite outage. Prioritized messages still need hard quotas, deadlines, and bounded client queues; otherwise an exemption can exhaust the system.
Wall and monotonic clocks
A wall clock maps to civil/epoch time and can jump because of correction. A monotonic clock measures elapsed time locally without wall-clock jumps, but its origin is not a shared global epoch.
Example. Use an epoch timestamp to label an event and a monotonic deadline to bound how long a process waits for the next usable timestamp.
Limit. Neither establishes causal order across machines. Monotonic readings cannot be compared between hosts or assumed to survive reboot with the same origin.
1. Requirements & Clarifying Questions
Start every design by pinning down scope. For an ad exchange, these questions change the design the most:
Who are we? The exchange (runs the auction for publishers) or a bidder (DSP, bids for advertisers)? This guide designs the exchange.
How many slots per auction? One banner (a simple second- or first-price auction) or a ranked list, like search ads (a position auction such as GSP)?
How do advertisers pay? Per impression (CPM), per click (CPC) or per conversion? This decides which event is billable.
What is the deadline? Usually around 100 ms end to end, set by the publisher.
What volume? Peak bid requests per second, and how many bidders each request fans out to.
Functional
Non-functional
Accept a bid request for an ad slot
Answer within the deadline (p99 < 100 ms)
Fan out to eligible bidders, collect bids
Very high throughput: hundreds of thousands to millions of requests/s
Pick a winner and a clearing price above the reserve
Billing accuracy: never charge for an ad that was not shown
Respect budgets and frequency caps
Highly available: a lost auction is lost revenue
Log impressions and clicks for billing
Fair: no bidder gets an unfair edge from the exchange
Intuition
Picture an auctioneer who must sell one painting in a tenth of a second. They shout the lot to every buyer at once, take whatever paddles go up before the gavel drops, and sell. Buyers who are still thinking when the gavel falls are simply out.
2. Back-of-Envelope Estimation
Assume a large exchange with 500K bid requests/s on average and 1M/s at peak. Each request fans out to about 20 bidders, and a request is about 2 KB of JSON.
Step
Working
Result
Peak outbound calls
1M requests/s × 20 bidders
20M calls/s
Outbound bandwidth
20M × 2 KB = 40 GB/s × 8
320 Gbps
Auctions per day
500K/s × 86,400 s
43.2B/day
Auction log
43.2B × 500 B per record
21.6 TB/day
Frequency-cap store
1B users × 20 campaigns × 50 B
~1 TB in RAM
Exchange servers
1M/s ÷ 5K auctions/s per box, +50% headroom
~300 servers
What the numbers tell you
The fan-out, not the request rate, is the real load. 320 Gbps of outbound traffic is why exchanges send a binary format (protobuf) instead of JSON, compress requests, and shape traffic: they only call bidders likely to bid on this kind of slot. The 1 TB frequency-cap store must be sharded across many in-memory nodes.
3. API & Data Model
Exchanges and bidders talk using the OpenRTB standard. A trimmed request and response look like this:
# exchange -> bidder: POST /bid
{ "id": "auc-81f2", "tmax": 100, # ms the bidder has
"imp": [{ "id": "1", "banner": {"w": 300, "h": 250},
"bidfloor": 0.50 }], # reserve, as CPM
"site": {...}, "device": {...}, "user": {...} }
# bidder -> exchange: 200 with a bid, or 204 = no bid
{ "id": "auc-81f2",
"seatbid": [{ "bid": [{ "impid": "1", "price": 1.25, "crid": "cr-9",
"adm": "<creative markup>",
"nurl": "https://dsp.example/win?p=${AUCTION_PRICE}" }] }] }
The nurl is the win notice. The exchange calls it with the real clearing price filled into the ${AUCTION_PRICE} macro, so the bidder learns what it paid.
Data
Key
Store
Why there
Campaigns: budget, targeting, cap
campaign_id
SQL, cached in memory on every server
Changes rarely, read on every auction
Spend so far today
(campaign_id, day)
In-memory counters, flushed to durable storage
Updated constantly, read by pacing
Frequency counts
(user_id, campaign_id)
Sharded in-memory KV with TTL
Read inside the deadline
Auctions, impressions, clicks
impression_id
Append-only log (Kafka), then a warehouse
Billing and reporting, off the hot path
Common mistake
Storing prices as floating-point dollars. Rounding errors add up over billions of auctions. Store money as integers in the smallest unit you need, often micros (millionths of a currency unit).
4. The Request Flow
The whole system is organized around a single short-lived event: an ad slot becoming available. A user loads a page, a slot on that page needs an ad, and the publisher's side sends a bid request to your ad exchange. From that instant a clock starts ticking, and everything that follows has to complete before it runs out.
An ad slot opens; the exchange builds a bid request and fans it out to many demand-side bidders in parallel. It collects whatever bids arrive inside the latency budget, runs the auction to pick a winner and a clearing price, and serves the winning ad, logging the impression for billing.
Reading the flow left to right:
Ad slot opens. A page or app impression triggers the request. The slot carries context — its size, placement, the page topic, and whatever non-identifying signals about the user are available.
Bid request. The exchange assembles a request describing the opportunity and prepares to ask the demand side what it is worth.
Fan-out to bidders. The request goes to many demand-side bidders (DSPs) at once, in parallel. Each one decides independently whether it wants this impression and, if so, how much to bid.
Collect bids. The exchange gathers the responses, but only those that arrive before the deadline. Anything slower is simply not part of the auction.
Run auction. Among the bids that made it back, the exchange selects a winner and computes the price the winner pays.
Serve winning ad. The winning creative is returned and rendered in the slot, and the impression is recorded so the advertiser can be billed.
function handle_bid_request(slot):
request = build_bid_request(slot) # context, size, signals
bids = fan_out_to_bidders(request) # parallel, deadline-bounded
winner = run_auction(bids)
if winner is None:
return NO_AD # slot stays empty or fallback
log.impression(winner, slot, price=winner.clearing_price)
return winner.creative
A useful reframing for an interview: RTB is a distributed auction on a deadline. Almost every design choice — the timeout, the parallel fan-out, the pacing, the tracking — exists to run a fair, money-moving auction inside a window so small the user can never perceive it.
5. Auction Mechanics
Specify currency, units (CPM/CPC), eligibility, reserve, deterministic ties, and deadline. In a textbook independent-private-value single-item Vickrey auction, the highest eligible bidder pays max(reserve,highest competing bid). Truthful bidding is a dominant strategy under that model. 'Second bid plus a cent' is a tick-rule variant, not exactly the continuous-price theorem.
First-price charges the winning bid and generally invites strategic shading. With one eligible bidder, exact second-price charges the reserve. Validate nonfinite/negative bids and use exact money units. Neither the pricing rule nor this tutorial describes every current exchange's internals.
6. Multi-Slot Auctions: GSP and VCG
When CPC bids rank by bid×predicted CTR, a generalized-second-price threshold uses the next bidder's score divided by the winner's quality (plus a documented tick/floor), not merely the next raw bid. The raw-next-bid rule applies to the equal-quality example.
GSP is not generally truthful: at CTRs 0.10,0.05 and values/bids 5,4,2, A earns 0.10 at truthful bidding but 0.15 by bidding 3.50 and taking slot 2. VCG charges each winner's externality and is truthful under its classical assumptions. VCG revenue is not universally less than GSP; $0.40 versus $0.50 is this example's result, not a general ordering.
7. The Latency Budget
The defining constraint of the whole system is the deadline. The auction is part of the user's page load, so the exchange gives the demand side a fixed, unforgiving window — commonly on the order of 100 milliseconds — to respond. A bidder that answers inside the window is in the auction. A bidder that does not is dropped, full stop.
Each bidder races against a fixed timeout. Bids that arrive before the cutoff are counted in the auction; a bidder that is even slightly late is simply dropped rather than waited on. The exchange runs the auction on whatever came back in time.
This "drop the slow ones" behavior is not a bug or a degradation — it is the correct design. The exchange cannot hold up the user's page waiting for a straggler, and it cannot let one slow bidder set the pace for everyone. A bidder that is consistently late is, from the auction's point of view, a bidder that does not exist. The practical consequences are worth stating plainly:
The timeout is firm. When the clock hits the deadline, the exchange stops collecting and runs the auction with whatever it has, even if that means fewer bidders competed.
Slowness is self-correcting in the wrong direction. A slow DSP simply wins fewer auctions, so the incentive to be fast is built into the market — but the exchange must not depend on bidders being well-behaved.
The budget is sub-divided. The 100ms is shared across network round-trips, the bidder's own computation, and the exchange's auction step, so each bidder's real compute window is even tighter than the headline number.
The headline 100 ms is shared. After parsing, two network trips, the auction itself and a safety margin, a bidder gets about 60 ms to decide. That is why tmax tells the bidder its real budget.
In RTB, latency is not a quality metric you tune later — it is the hard boundary the entire architecture is built around. "Be fast or be excluded" is the rule, and the exchange enforces it by never waiting past the cutoff.
8. Fan-Out and Gather
Because the exchange must consult many bidders but cannot afford to ask them one after another, the requests go out in parallel and the responses are gathered with a single shared deadline. Calling bidders sequentially would stack their latencies and blow the budget after just two or three; calling them concurrently means the total wait is the time of the slowest bidder you are still willing to wait for — which is exactly the timeout.
The pattern is a scatter-gather: dispatch the bid request to every eligible bidder at once, then collect responses until the deadline arrives, then stop. The crucial detail is that the gather step is bounded by the clock, not by the number of bidders. You do not wait for all of them; you wait until time runs out and take whatever has arrived.
function fan_out_to_bidders(request):
deadline = now() + 100ms
futures = [send_async(bidder, request) for bidder in eligible_bidders]
bids = []
for f in futures:
remaining = deadline - now()
if remaining <= 0:
break # deadline hit: stop collecting
try:
bid = f.result(timeout=remaining) # never wait past the deadline
bids.append(bid)
except Timeout:
continue # drop the slow bidder
return bids # whatever made it back in time
This is also where isolation matters: a single hung bidder must never be able to stall the gather. Per-call timeouts, dropping rather than retrying within an auction, and treating a missing response as simply "did not bid" keep one misbehaving DSP from poisoning the whole auction. There is no time for retries inside a single auction — the deadline is the retry policy.
9. Budget Pacing
Pacing adjusts bids/participation toward a forecast traffic-weighted spend target. It is a feedback policy, not a hard budget proof. Delayed cost reports, concurrent wins, and forecast errors can overshoot.
For a hard ceiling, atomically account for finalized spend plus outstanding reservations. Distributed allocations must be disjoint and safely reclaimed; an expired holder can still return a delayed result. A 95% cutoff is a heuristic unless exposure cost/delay is rigorously bounded. When CPC cost is uncertain, reserve conservatively or document a permitted bounded overspend contract.
10. Frequency Capping
Frequency capping limits measured exposures per user/campaign/window. Define whether an exposure means rendered, viewable, or a callback-confirmed impression; identify the user/session scope and explain privacy/identity resets. A low-latency counter can support a soft cap, but concurrent auctions and delayed reports can overshoot.
For a hard cap, reserve exposure allowance atomically before permitting the effect, account for outstanding reservations, and settle/release them through idempotent event identities. A check before bidding followed by a later increment is racy. Atomic increment only after delayed callbacks is not enough to prevent prior concurrent exposures. Safe allocation/reclaim requires a defined failure/uncertainty horizon; fail-open or lost replicated state weakens the bound.
Fixed calendar and trailing-window caps differ; resetting TTL on each increment implements neither automatically. Store explicit window-start/expiry or timestamped contributions and define exact boundaries. Benchmark the counter path and decide how unavailable identity/state changes behavior rather than pretending every cap is exact.
11. Tracking for Billing
An ad auction moves real money, so the system must record what actually happened with enough fidelity to bill advertisers correctly. The two events that matter most are impressions (the ad was shown) and clicks (the user engaged), and depending on the pricing model the advertiser is charged on one or the other.
Tracking is harder than it sounds because the events fire on the user's device, far from your servers, and arrive as a high-volume firehose. The design has to be durable and resistant to double-counting: a winning bid is logged at serve time, an impression event confirms the ad was actually rendered, and a later click event ties back to the same impression. These flow into a pipeline that aggregates spend per advertiser and reconciles it against budgets.
Impression tracking. When the creative renders, a tracking pixel or callback reports it. This confirms the slot was filled and is the billable event under CPM pricing (cost per mille: the price is quoted per thousand impressions, so one impression costs CPM / 1000).
Click tracking. A click is attributed to the impression that produced it, and is the billable event under cost-per-click (CPC) pricing.
Reconciliation. Aggregated impression and click counts feed back into the pacing and budgeting systems so spend is accurate and an advertiser is never overcharged.
Billing demands the same discipline as any money system: durable logs, idempotent event handling keyed by a request or impression id, and reconciliation. An auction you cannot account for afterwards is an auction you cannot charge for.
12. Scale and Parallelism
The last thing to reckon with is volume. A large exchange handles enormous numbers of bid requests per second, and each one fans out to many bidders — so the real load is requests multiplied by bidders, all under the same hard deadline. That product is what forces nearly every scaling decision in the system.
Parallelize the fan-out. Every auction's bidder calls run concurrently, never sequentially, so the per-auction latency is bounded by the timeout rather than by the number of bidders.
Horizontal scale-out. The exchange is stateless per request and runs as a large pool of identical servers behind a load balancer, so throughput scales by adding machines.
Put hot data in memory. Pacing state, frequency counters, and budget balances are read on the critical path, so they live in fast in-memory stores rather than a disk-bound database that would blow the budget.
Move billing off the hot path. Impression and click events are written to a durable queue and aggregated asynchronously, keeping the latency-critical auction path lean.
The unifying idea is that anything on the auction's critical path must be fast and parallel, and anything that can tolerate a small delay — billing aggregation, reporting, reconciliation — is pushed off that path into asynchronous pipelines. The deadline is sacred; everything else bends around it.
13. Failure Modes
What fails
What happens
How to handle it
A bidder is slow or down
Its bids miss the deadline
Per-call timeout; a circuit breaker stops sending to it; cut its traffic share until it recovers
An exchange server crashes mid-auction
That auction is lost
Publisher shows a fallback ad; servers are stateless, so the load balancer routes around it
Traffic spike beyond capacity
Queues grow, deadlines slip for everyone
Shed load early: answer "no bid" to some requests instead of being late on all of them
Budget counters lag behind real spend
Campaign overspends while updates are in flight
Give each server a small slice (lease) of remaining budget; stop bidding near 95% of budget
Frequency store shard down
Cannot read caps for some users
Pick a policy: fail open (serve, risk extra exposure) or fail closed (skip, lose revenue)
Impression pixel fires twice
Advertiser billed twice
Dedup on impression_id in the billing pipeline
14. Tradeoffs & Alternatives
Choice
Option A
Option B
Usual pick
Pricing rule
Second price: easy bidding, opaque price
First price: transparent, bidders must shade
First price for display today; GSP-style for search
Who to call
Every bidder: max competition
Only likely bidders: less bandwidth
Traffic shaping, since fan-out cost dominates
Budget check
Synchronous, strongly consistent
Local slices, async reconcile
Local slices; a small bounded overspend is fine
Wire format
JSON: easy to debug
Protobuf: smaller, faster to parse
Protobuf at high volume
Frequency cap on store failure
Fail open
Fail closed
Depends on whether the cap is a promise or a preference
Worked example: a profitable GSP bid deviation
Two equal-quality slots have click rates 0.10 and 0.05; click values are A=$5, B=$4, C=$2.
Read top to bottom. The table below explains the state and guarantee at each step.
Step
State, calculation, and reasoning
1. Allocate truthful bids
A wins first, B second, paying $4 and $2 per click. Revenue is 0.10×4+0.05×2=$0.50 per view.
2. Compute A's utility
A earns 0.10×(5−4)=$0.10 per view.
3. A shades to $3.50
B wins first; A wins second at $2, earning 0.05×(5−2)=$0.15 per view.
4. Interpret the deviation
GSP is not generally truthful. Quality-weighted thresholds and budget enforcement must be specified separately.
Check your understanding: What must a hard budget account for beyond observed spend?
Outstanding reserved/allocated exposure cost. Delayed spend counters and a pacing curve alone can overshoot.
Run a small, testable model
Download concepts.py. It uses only the Python 3.10+ standard library. From the directory where you saved it, run:
python3 concepts.py auction
python3 concepts.py test
The model computes textbook second price and reproduces the GSP utility counterexample.
The program contains deterministic assertions and failure traces. It is a learning model, not a production service: it does not implement network consensus, distributed durability, authentication, or third-party delivery. Read its contracts and try changing an input before extending it.
Deep dives: the deadline and scatter-gather, the pricing rule and why it changes bidding, pacing, frequency caps.
35–42
Failures and tradeoffs: slow bidders, overspend, double-counted impressions.
42–45
Recap the design against the requirements, then name what you would build next.
Interview tip
Interviewers love the question "why not wait a little longer for more bids?" Answer with the user: the auction is part of the page load, and a slower page loses more money than one extra bidder brings in.
16. Common Mistakes
Calling bidders one by one, or waiting for all of them. Fan out in parallel and stop at the deadline.
Retrying a timed-out bidder inside the same auction. There is no time. The deadline is the retry policy.
Billing on the win instead of the rendered impression. Many won ads are never shown, for example when the user scrolls away first.
Putting a strongly consistent budget database on the per-bid path. It cannot keep up. Use local slices and reconcile.
Calling GSP truthful. Only single-slot second price and VCG are.
Ignoring fan-out in the estimate. Requests × bidders is the real load.
17. Summary
An ad auction is a distributed, money-moving auction that has to finish inside a window the user can never perceive. Its design is a set of decisions that all serve that deadline:
Concern
Mechanism
What kicks off an auction?
An ad slot opening triggers a bid request describing the opportunity.
How do we get prices from the market?
Fan the request out to many demand-side bidders in parallel.
Who wins and what do they pay?
An auction: first-price (pay your bid) or second-price (pay just over the runner-up), above a reserve.
How do we stay within the deadline?
A hard latency budget (~100ms); bidders that respond late are dropped, never waited on.
How do we ask everyone at once?
Scatter-gather fan-out bounded by the clock, not by the bidder count.
How do we keep budgets from burning out early?
Budget pacing: a control loop that smooths spend across the day.
How do we avoid annoying users?
Frequency capping via fast per-user, per-campaign counters.
How do we charge advertisers?
Durable, idempotent impression and click tracking feeding a billing pipeline.
How do we handle the volume?
Parallel fan-out, stateless horizontal scale-out, in-memory hot data, async billing.
The recurring theme: the latency budget governs everything. Bidders are called in parallel and dropped when late, hot state lives in memory, billing is pushed off the critical path, and pacing and capping keep the market healthy — all so a fair auction can run and an ad can be priced and served before the page finishes loading.
18. Check Yourself
In a single-slot second-price auction, why is bidding your true value the best strategy?
Answer
Your bid only decides whether you win, not what you pay (the runner-up sets the price). Bidding higher only adds wins where the price is above your value, which lose money. Bidding lower only loses auctions you would have won at a profit.
Bids are $3.00, $2.40 and $1.10, and the reserve is $2.50. What does the winner pay under first price, and under the page's second-price code?
Answer
Only $3.00 clears the reserve. First price: $3.00. Second price: there is no eligible runner-up, so the price falls to the reserve, $2.50.
At 1M requests/s, 20 bidders each and 2 KB per request, what is the outbound bandwidth? Name two ways to cut it.
Answer
20M calls/s × 2 KB = 40 GB/s = 320 Gbps. Cut it with traffic shaping (only call bidders likely to bid) and a compact wire format such as protobuf with compression.
A campaign has a $2,400 daily budget. A quarter of the day's expected traffic has passed and it has spent $900. What should pacing do?
Answer
Target spend is 2,400 × 0.25 = $600. Actual spend of $900 is 1.5× the target, so pacing should throttle down, by lowering bids or entering fewer auctions.
Why can the exchange not simply retry a bidder that timed out?
Answer
The deadline has already passed for that auction. A retry would make the page wait, and the auction must run with whatever arrived in time.
Using the GSP example on this page, show that bidder A gains by lying.
Answer
Truthful: A wins slot 1, pays $4 and earns 0.10 × (5 − 4) = $0.10. If A bids $3.50, it takes slot 2, pays $2 and earns 0.05 × (5 − 2) = $0.15, which is more.
19. Key Terms
RTB
Real-time bidding: an auction run for each ad impression as the page loads.
Exchange / SSP
Runs auctions for publishers' ad slots.
DSP
Demand-side platform: bids on behalf of advertisers.
Reserve (floor)
The lowest price the publisher will accept.
Clearing price
What the winner actually pays.
Bid shading
Bidding below your value in a first-price auction to avoid overpaying.
GSP
A pricing rule connects bids to allocation and payment. First-price charges the winning bid. A textbook single-item second-price auction charges the highest competing bid, subject to a reserve and specified tie rule. Generalized second price handles ranked multiple slots. Example and limits above.
VCG
Winners pay the harm they cause others. Truthful.
eCPM
Expected revenue per thousand impressions; for CPC bids, bid × pCTR × 1000.
CPM / CPC
Price per thousand impressions / price per click.
Pacing
Spreading a budget across the day.
Frequency cap
Limit on how often one user sees one campaign.
Win notice
Callback telling the winning bidder the clearing price.
20. Further Reading
IAB Tech Lab, OpenRTB API Specification (versions 2.5/2.6 and 3.0).
W. Vickrey, "Counterspeculation, Auctions, and Competitive Sealed Tenders," Journal of Finance, 1961.
B. Edelman, M. Ostrovsky, M. Schwarz, "Internet Advertising and the Generalized Second-Price Auction," American Economic Review, 2007.
H. Varian, "Position Auctions," International Journal of Industrial Organization, 2007.
D. Easley, J. Kleinberg, Networks, Crowds, and Markets, chapter 15, "Sponsored Search Markets."