Search for a PRD example and you mostly get blank templates. A heading that says Objective, an empty bullet list underneath, and a note telling you to describe your objective. That's a form, not an example. The hard part of writing a product requirements document isn't knowing that it needs an objective section. It's knowing how specific that objective has to be before an engineer can act on it.
So this page does the opposite. Below is a complete PRD for a product that doesn't exist, written the way I'd write it for a real build, followed by notes on why each section says what it says.
The product: a waitlist tool that helps dental clinics fill last-minute cancellations. Concrete enough to be useful, small enough to fit on one page.
The PRD
MVP Specs: Chairfill
How to read this spec
- Everything under Features gets built. Everything under Constraints does not, no matter how small it seems.
- A feature is done when every acceptance criterion under it passes, not when the code runs.
- If a requirement here is ambiguous, stop and ask rather than guessing.
- P0 features block launch. P1 and P2 do not.
- Build in the order given under Build order, not in the order features are listed.
- If something in this document turns out to be wrong, change this document first, then the code.
Objective
Dental clinics lose revenue every time a patient cancels within 24 hours, because the empty chair almost never gets refilled. Front-desk staff currently work down a paper list and phone patients one at a time, which takes long enough that they usually give up after three or four calls.
Chairfill fills that chair automatically. When an appointment is cancelled, patients who asked to be seen sooner get a text with the open slot, first to claim it takes it, and the clinic's calendar updates.
This works if a clinic that installs it refills at least half of its short-notice cancellations without anyone picking up the phone.
Product ICP
Single-location dental practices in the US with two to five chairs and one front-desk employee. They already run practice-management software (Dentrix, Eaglesoft, or Open Dental) and won't replace it. The person who feels the pain is the front-desk employee. The person who pays is the practice owner, who sees cancellations as lost revenue rather than as an admin problem.
Not for: multi-location dental service organizations, medical practices outside dentistry, or clinics that don't keep any kind of waitlist today.
Constraints: do not build
- A full scheduling system. The clinic keeps its existing practice-management software. Chairfill reads and writes appointment slots and owns nothing else.
- Why excluded: replacing scheduling is a multi-year product and the reason clinics will refuse to install this.
- A patient mobile app. Patients claim slots through a plain web link in a text message.
- Why excluded: nobody installs an app for their dentist. It would sink the claim rate.
- Payments. No deposits, no card capture, no billing.
- Why excluded: the clinic already collects payment at the visit. Adding money to the MVP adds compliance work and buys nothing.
- Multi-location support, roles, and permissions. One clinic, one login.
- Why excluded: the ICP has one front desk. Roles are the first thing to add if a DSO ever signs up, and the first thing to regret if we build them now.
Features
Must: MVP core
P0 · Waitlist capture
Front-desk staff can add a patient to the waitlist with name, phone number, and the treatment type they're waiting for.
- Why it's core: without a list of people who want an earlier slot, there is nobody to notify.
- Solves: the paper list that lives on one person's desk and disappears when they're off.
- Complexity: small
- Acceptance criteria:
- A patient can be added in under 15 seconds from the main screen.
- Phone numbers are validated as US mobile numbers on entry, with an inline error on failure.
- Duplicate phone numbers are flagged before saving, not after.
- The list survives a page refresh and is visible to any logged-in user at that clinic.
P0 · Cancellation trigger
When an appointment is cancelled in the clinic's practice-management software, Chairfill detects the open slot within five minutes.
- Why it's core: this is the event the whole product hangs on. Manual entry of cancellations was tested with two clinics and neither did it consistently.
- Solves: the delay between a cancellation and anyone noticing the chair is empty.
- Complexity: large
- Depends on: Waitlist capture
- Acceptance criteria:
- Detects a cancellation in Open Dental within five minutes of it happening.
- Captures slot start time, duration, and provider.
- Ignores cancellations more than 72 hours out, which the clinic can refill normally.
- Logs every detected slot so a missed fill can be traced afterwards.
P0 · Slot offer by SMS
Matching waitlist patients get a text with the open slot and a link to claim it. First to claim wins.
- Why it's core: the offer is the product. Everything else is plumbing around it.
- Solves: the front desk phoning patients one at a time until they give up.
- Complexity: medium
- Depends on: Cancellation trigger
- Acceptance criteria:
- Offers go only to patients whose treatment type matches the open slot.
- Up to five patients are texted at once, in waitlist order.
- The claim link expires when the slot is taken or 60 minutes pass, whichever comes first.
- A patient who claims a taken slot sees a clear "already filled" message rather than an error.
- Every patient is texted at most twice per week, regardless of how many slots open.
P0 · Claim confirmation
When a patient claims a slot, the appointment is written back to the clinic's software and both sides get a confirmation.
- Why it's core: a claim that doesn't reach the calendar creates a double-booking, which is worse than the empty chair.
- Solves: the manual re-entry step that would otherwise land back on the front desk.
- Complexity: medium
- Depends on: Slot offer by SMS
- Acceptance criteria:
- The appointment appears in the clinic's software within 60 seconds of the claim.
- The patient receives a confirmation text with date, time, and clinic address.
- If the write-back fails, the front desk gets an alert naming the patient and slot, and the patient is told the clinic will confirm shortly.
- The claimed patient is removed from the waitlist automatically.
Should: important, not blocking v1
P1 · Fill-rate dashboard
A single screen showing slots opened, slots filled, and revenue recovered this month.
- Why it's here: this is what the practice owner looks at when deciding whether to keep paying. It isn't needed to prove the product works, so it can land in week five.
- Complexity: small
- Depends on: Claim confirmation
- Acceptance criteria:
- Shows slots opened, slots filled, and fill rate for the current month.
- Revenue recovered uses a per-treatment value the clinic enters once.
- Loads in under two seconds with a year of data.
Could: nice to have
P2 · Waitlist self-signup
A link the clinic can text to patients so they add themselves to the waitlist.
- Why it's here: removes data entry from the front desk, but only matters once clinics have proven they'll use the waitlist at all.
- Complexity: small
- Depends on: Waitlist capture
Build order
Phase 1, no dependencies: Waitlist capture.
Phase 2: Cancellation trigger, which is the riskiest item in the document and should be attempted in week one even though it isn't first in the list.
Phase 3: Slot offer by SMS, then Claim confirmation.
Phase 4: Fill-rate dashboard, then Waitlist self-signup.
Open questions
- Does Open Dental's API expose cancellations as events, or does this need polling? Answer before starting Phase 2.
- What happens when two clinics share a patient phone number? Rare, but it breaks the "at most twice per week" rule.
Why the example is written that way
The structure above isn't decorative. Each section is doing a job that shows up later as either saved time or a rebuilt feature.
The objective ends with a number. "Refills at least half of its short-notice cancellations without anyone picking up the phone" is a sentence you can be wrong about. Compare it to "streamline appointment management for dental practices," which nobody can ever disprove and which gives an engineer no way to choose between two implementations. If your objective can't be false, it isn't an objective.
The ICP names a person, not a segment. "Single-location practices with two to five chairs and one front-desk employee" rules things out. It tells you the login model (one clinic, one account), the support expectations, and why roles and permissions are absent. A PRD that says "for dental professionals" would have left all three of those decisions to whoever writes the code, at 2am, without asking.
The out-of-scope section has reasons attached. Writing "don't build payments" invites someone to add payments in week three when it seems easy. Writing "don't build payments, because the clinic already collects at the visit and it adds compliance work" survives the argument. Every exclusion here is a decision someone would otherwise relitigate.
Acceptance criteria are written as tests, not wishes. "Detects a cancellation within five minutes" can be verified. "Reliably detects cancellations" cannot. The rule I use: if you can't imagine the check that proves it, rewrite the criterion. Notice too that several criteria describe failure paths, like the write-back alert and the "already filled" message. Failure paths are where most specs go quiet and most builds go wrong.
The riskiest feature is called out in the build order. The list puts waitlist capture first because nothing depends on it, but the build order pulls the integration into week one. The point of sequencing is to find out early whether the thing that could kill the product actually works. If Open Dental turns out not to expose cancellations, everything else in the document is worthless, and you want to know that in week one rather than week six.
Open questions are in the document. Every project has them. Leaving them out doesn't resolve them, it just moves them into somebody's head where they get answered silently by whoever hits them first.
Writing a PRD an AI coding agent can build from
If a coding agent is doing the implementation, a few things in the example change from good practice to load-bearing.
The "how to read this spec" block at the top exists because agents follow instructions literally and benefit from being told the rules of engagement before the content. Two of those rules matter more than the rest: build only what's listed, and stop and ask rather than guessing. Left unsaid, an agent fills ambiguity with plausible invention, and plausible invention is expensive to unwind.
The out-of-scope section does more work here than with a human team. A human engineer given a spec without a settings page will ask whether you want one. An agent will often just build it, along with a notifications system and an admin panel, because those things co-occur with the features you asked for in everything it has ever read. The constraints section is the counterweight.
Acceptance criteria as checkboxes also serve a second purpose with agents: they're the thing you point at when the output doesn't match intent. "Criterion three fails" is a far more productive instruction than "this isn't quite right."
This is the same reasoning behind spec-driven development, which is worth reading if the agent is doing most of the typing.
What a weak PRD looks like
For contrast, the same product specced badly:
Objective: Build a modern, intuitive platform that helps dental practices optimize their scheduling workflow and improve patient satisfaction.
Features: Waitlist management, smart notifications, calendar integration, analytics dashboard, patient portal, admin settings.
Nothing there is false. Nothing there is buildable either. There's no user named, no way to tell whether the thing worked, no indication which of the six features matters most, and no signal that "calendar integration" is a month of work while "waitlist management" is two days. Handed to an engineer, it produces six half-features. Handed to an agent, it produces six half-features faster.
The gap between the two versions isn't length. It's that every sentence in the first one could be wrong, and every sentence in the second one is safe.
Adapting this to your product
Keep the section order and replace the content. The parts that transfer without modification:
- The "how to read this spec" block, if an agent is building.
- The must/should/could grouping with P0/P1/P2 inside it.
- Acceptance criteria as checkboxes, including at least one failure path per feature.
- The out-of-scope list with a reason on every line.
- A build order that front-loads the riskiest unknown.
The parts you have to earn rather than copy are the objective and the ICP, because both depend on evidence you can only get by talking to the people who have the problem. A PRD built on an assumed user is a very organized way to build the wrong thing. That's the work that comes before this document, and it's worth doing first: how to validate a business idea covers the cheap version.