Prices must react to demand within seconds, and two users looking at the same item must not see different prices. Which do you give up?
Real-time pricing system design should publish numbered price versions instead of calculating a different answer per request. Compute prices by region and time window, serve the current version consistently, and freeze quotes briefly so users are not surprised during checkout.
What the interviewer is scoring
- Does the candidate refuse the false choice and show which property is genuinely being traded
- Whether price is modelled as a published versioned artefact rather than computed per request
- That the quote given to a user is stored with an expiry and honoured until it lapses
- Can they name the cache layer as the mechanism by which two users end up disagreeing
- Whether auditability comes up unprompted, given that a user will ask why they paid what they paid
Answer
Short answer
Compute prices in batches, publish each batch as a version, serve one current version per market, and honour short-lived quotes even while the next version rolls out.
The question contains a false choice, and saying so is the answer
Take the constraints literally for a moment. "React within seconds" and "two users must agree" only conflict if the price is computed per request, because then the two users are two computations that happened at different instants with different inputs. Stop computing per request and the conflict dissolves.
Price becomes a published artefact. A pricing job computes a number for a unit of the market — a region, a product, a short time window — and publishes it. Every viewer reads the published number. Two users looking at the same item in the same region get the same value because they are reading, not calculating. What you gave up is not agreement and not reaction time. It is instantaneous propagation: for a few seconds after a change, some readers still hold the previous version.
That is the trade an interviewer wants named. Freshness of a particular reader's copy, in exchange for every reader agreeing with every other reader who is looking at the same version.
The petrol station sign is the analogy. Whatever is on the sign is the price for everyone who can read it, and nobody computes a personal figure at the pump. The sign changes when someone changes it, and for a minute the number on the forecourt differs from the number head office decided. Where the analogy breaks is that a station has one sign, whereas a website has a sign in every cache in every region, and nothing makes them all change in the same second.
What the pipeline looks like
Demand and supply signals arrive as events: searches, views, requests, inventory levels, competitor feeds. A streaming aggregation reduces them per region per short window. A pricing function turns those aggregates into a number, applying whatever floors, ceilings and smoothing the business requires. The result is written as a new row rather than an update in place.
Do the arithmetic on the cost, because candidates usually overestimate it. Say four hundred regions and a recompute every thirty seconds. That is 400 × 2, so eight hundred price computations a minute, over aggregates that a stream processor is already maintaining. On a single machine that is nothing. Computing prices is not the hard part of dynamic pricing.
Distributing them coherently is. That is where the engineering goes.
-- Prices are appended, never updated. Serving reads the newest row whose
-- effective_from has passed, so a version can be prepared before it applies.
INSERT INTO price_versions
(region_id, product_id, version, amount, currency, effective_from, model_id, inputs_digest)
VALUES (:region, :product, :version, :amount, 'GBP', :effective_from, :model, :digest);
Two details in that table earn their place. The version number gives every quote something durable to point at, so a support agent can reconstruct exactly what a user was shown. And the digest of the inputs makes the price explainable later without storing the whole feature vector on every row, which matters because "why was I charged this" is a question you will be asked by users, by your own analysts and possibly by a regulator.
Caches are how two users come to disagree
The mechanism that breaks the agreement constraint is almost never the pricing job. It is the layer in front of it.
Put a sixty-second time-to-live on a price response at the edge and you have created the failure directly: two users in the same city, routed to different points of presence, hold copies fetched at different times. Neither cache is wrong. The constraint is broken anyway, and it is broken invisibly, because each server can show you a correct log line.
There are two defensible resolutions. Serve prices from one authority per region with a very short cache lifetime, accepting the read load, which is manageable because the number of distinct prices is small even when the number of viewers is large. Or cache aggressively but cache the version pointer separately with a short lifetime, so a client fetches "current version for this region" cheaply and then fetches the version's contents from a cache that can live for hours because a version is immutable. The second shape is usually better: immutable content caches perfectly, and only the tiny pointer needs to be fresh.
Whichever you pick, the rule to state is that a price must never be cached under a key that does not include its version. That single discipline turns cache coherence from a race into a lookup.
The quote is the contract, not the price
A price is what the market says. A quote is what you promised a specific user, and the difference is what makes the whole design survive a page that stays open.
When a user views the item, they receive the current price along with a quote identifier and an expiry, and that quote is written down. For its lifetime, that user pays that number. When the expiry passes, the client is required to refresh before checkout. Nothing reprices under someone mid-transaction, and nothing has to be honoured forever.
Choosing the lifetime is a business decision with an engineering consequence. Long quote lifetimes are kind to users and expose you to arbitrage, because a script can hold thousands of quotes and exercise only the ones the market moved against you. Short lifetimes protect the margin and produce the experience everybody hates, where the total changes between the basket and the card form. The usual settlement is a lifetime measured in a few minutes, bounded by requiring the quote to be presented at the moment of payment rather than earlier, and a limit on how many outstanding quotes one account can hold.
Reprice at checkout only when the quote has genuinely lapsed, and when you do, show the old and new figures rather than silently substituting. A user who sees "the price changed while you were deciding, here is the difference" forgives it. A user who notices a different number on their statement does not.
Where this design goes wrong
The per-request price is the first error and the visible one. It also destroys auditability: with no version, there is nothing to point at when the numbers are questioned, and the answer becomes an attempt to re-run a model against inputs that have moved on.
The second is subtler and does more damage. Reacting to demand within seconds with no smoothing produces a price that oscillates, because the demand signal itself is noisy at that resolution and your own price changes feed back into it. High price suppresses demand, low demand lowers the price, the price falls, demand returns. Users see a number that flickers, which reads as either broken or manipulative. Rate-limit the change per interval, apply a floor and a ceiling, and require a minimum dwell time before a version can be superseded. Reacting in seconds is a requirement about how fast you can move when you need to, not a licence to move constantly.
Stop computing a price per request and publish a versioned one instead: agreement becomes a property of reading the same immutable version, and the only thing you conceded is that the change takes a few seconds to reach every cache.
© 2026 Preptima. Originally published at preptima.com.
Likely follow-ups
- A user holds a quote for ninety seconds while the price doubles. Do you honour it, and what stops that being exploited by a script?
- Two users are in different countries and the item is priced per region. How do you decide which region a viewer belongs to, and what happens when that answer changes mid-session?
- The pricing model needs a feature that takes two minutes to compute. Where does it go so it does not slow the serving path?
- How would you roll out a new pricing model to one per cent of regions without two nearby users seeing different prices for the same item?
Related questions
- Marketing want to raise the price of a plan a million subscribers are already on, and change what it includes. What has to happen in the catalogue?hardAlso on versioning5 min
- How would you build a rating engine, and how do you reproduce a quote you gave someone eighteen months ago?hardAlso on versioning5 min
- The business wants to change a rating factor next Monday. Walk me through what actually has to happen.hardAlso on versioning5 min
- How do you decide whether a model should be served in batch, online or streaming?mediumAlso on streaming4 min