Two people book the last seat at the same moment. Neither is allowed to see a failure after paying. What happens?
Preventing double booking seats means claiming the seat before payment, not racing two payments and reconciling later. A short atomic hold serialises buyers, payment only starts for the winner, and uncertain payment outcomes are settled by reconciliation rather than silent expiry.
What the interviewer is scoring
- Whether the answer puts the inventory claim before the payment and explains what that ordering buys
- Does the candidate describe what each of the two users sees, and at what point in the flow
- That a hold carries an owner and an expiry rather than being a boolean on the seat
- Whether the payment-pending hold is excluded from expiry-driven release
- Can they say what the recovery is once money has been taken and the seat is genuinely gone
Answer
Short answer
Create an atomic short-lived hold on the seat, send only the holder to payment, reject everyone else at selection time, and reconcile unknown payment outcomes before releasing the hold.
The constraint is about ordering, not about locking
Read the second sentence of the question again. Nobody may see a failure after paying. That is not a database requirement, it is a statement about where in the sequence the bad news is allowed to appear.
Which means the design writes itself in one move: take the money after the seat is secured, never before. If payment comes first and inventory second, then the losing user has already been charged when you discover the seat is gone, and every recovery from that point is a refund and an apology. A refund is a visible failure. It arrives days later, it involves a support conversation, and the user tells other people about it.
So the refusal moves upstream. Both users click the last seat. Both attempt a claim. One gets it and proceeds to the card form. The other is told, before any payment interface appears, that the seat has just gone, and is shown the seat map with alternatives. That user has had a disappointing experience and not a failed one, and the distinction is the entire answer.
Say this plainly in an interview, because it separates the ordering insight from the mechanics: "A race for the last seat should be lost at selection, not at settlement."
The claim itself
The seat needs one authoritative record with serialised transitions, and the claim has to be a single operation that both checks and mutates. A conditional update that sets the seat to held with this owner and this expiry, only where the seat is currently free or where an existing hold has already lapsed, and you read the affected row count as the verdict. One row means you hold it. Zero means somebody else does.
The hold needs three things and candidates routinely supply only the first. A state, so the seat is not available. An owner, so a second request from the same user resumes their own hold instead of being refused. And an expiry, so a user who wanders off does not remove inventory from sale permanently.
Everything the user is shown flows from those states. Available seats are selectable. A seat you hold shows a countdown, because a hidden timer that lapses silently is the source of the worst version of this experience: a user completing a card form against a seat they no longer have. A seat held by someone else is drawn as unavailable, and refreshing does not get it back.
sequenceDiagram
participant A as Buyer A
participant B as Buyer B
participant S as Booking service
participant P as Payment provider
A->>S: claim last seat
B->>S: claim last seat
S-->>A: held for 8 minutes
S-->>B: seat gone, pick another
A->>S: pay
S->>P: authorise
P--xS: timeout, outcome unknown
Note over S: hold stays in payment pending<br/>reconciliation decides, not expiryThe line to look at is the one that never reaches the card form. Buyer B is refused while still on the seat map, which is the whole design goal, and everything after it concerns only the buyer who won.
The hold that must not expire
Now the hard case, which is where an answer stops being a textbook one. Buyer A submits payment. You call the provider. The connection times out and you do not know whether the charge succeeded.
Two obvious moves are both wrong. Releasing the seat because the hold has expired risks selling it again to someone else while a successful charge sits on Buyer A's card, which is the exact failure the question forbids. Retrying the authorisation blindly risks charging twice.
So the hold enters a state of its own: payment pending, owned by a specific payment attempt with its own identifier. Holds in that state are excluded from expiry-driven release. They are resolved by asking the provider about that attempt identifier until it gives a definite answer, and only then does the seat become sold or return to available. The distinction to articulate is between a hold nobody is using, which expiry should reclaim, and a hold whose fate is unknown, which only reconciliation can settle.
That also means the timer the user sees and the lifetime of the hold are not the same thing. The countdown expires the checkout session. The hold survives into reconciliation if a payment was attempted. Conflating those two produces the release-while-charging bug, and it is the single most common flaw in an otherwise sound answer.
What you do when it happens anyway
An interviewer may press: suppose the money moved and the seat is gone. What then?
Do not pretend the design prevents it. It reduces the probability; it does not reach zero, because a stale inventory read, an oversell during a failover, or a bug can all produce it. Once it has happened, the response is policy, not code. Refund in full and rebook at your cost on the next available option, upgrade if that is what is available, notify the user before they discover it themselves, and make the decision automatic up to some value so that the recovery does not wait on a human. Write that policy down and implement it as a path in the system, with a queue somebody watches.
Then measure it. The number of bookings that took money and could not be honoured is the metric this design exists to keep at zero, and it should be on a dashboard rather than inferred from complaints.
Deliberate overbooking is worth separating from all of this. Airlines sell more seats than they have on purpose, with a compensation budget and a legal framework behind it, and that is a business decision with a known cost. It is not the same thing as an accidental double-sell, and using it to excuse one is the answer an interviewer stops trusting.
The idea that has to survive the whole design
Two independent claims on a single unit of inventory need one serialisation point, and that point has to be the record itself. Not a cached count, not an application-level check, not an availability number computed from a replica. Those all produce the same failure in different clothes: two callers both believing the seat is free.
Everything else in the design is about making the consequence of losing that race land early and land gently.
Order of operations is the requirement: claim inventory, then take money, and a hold whose payment outcome is unknown belongs to reconciliation rather than to a timer.
© 2026 Preptima. Originally published at preptima.com.
Likely follow-ups
- The user abandons the card form with a hold outstanding and returns eleven minutes later. What do they see, and what did the system do in between?
- Your inventory count is served from a read replica two seconds behind. Which user-visible promise does that break first?
- The business wants deliberate overbooking on some routes. What changes in the model, and what must not change?
- A single booking covers four seats and only three are available. Where does that partial failure surface, and what is the user offered?
Related questions
- A payment API times out and the client retries. How do you guarantee the customer is not charged twice?hardAlso on payments6 min
- Design ticketing for a 60,000-seat stadium where every seat goes on sale at 10am. How do you sell each seat exactly once?hardAlso on inventory7 min
- Two customers try to buy the last item at the same time. How do you handle inventory?hardAlso on inventory6 min
- When do you take the customer's money, and how much fraud are you willing to accept?hardAlso on payments7 min