Should I vibe code
Online booking system with websites, reminders, payments, and add-ons
You would not be writing a scheduler. You would be writing the till at somebody else's front desk.
?
Their verdict, the Standard price and the build-time estimate come from their entry, MIT-licensed. Checked 2026-08-04.
?
Our verdict, the regret score and everything below it. Editorial and unsponsored — nobody can pay to be moved.
The honest answer
why the verdict is what it is
Calendly hands out a link; SimplyBook.me runs a front desk, and that gap is the whole entry. Its plans meter providers, locations and bookings per month, and its feature list reads like a shop counter: deposits, tips, a point of sale, class registrations, memberships, ten-session packages, gift cards. Several of those are stored value, which is the part people underestimate — a package balance is money you are holding on somebody else's behalf, decremented by a column in your schema, and the disagreement about whether it is right happens at a counter with a customer standing there rather than in your inbox on Monday. Layered on top is the reason the vendor sells HIPAA compliance with a signed BAA from its middle tier upwards: salons, dentists and therapists buy the same product, and a clinic's intake question is "anything we should know about?". So the honest description of what you would ship is a public endpoint that takes strangers' money, holds their prepaid balances, sometimes holds their medical history, and belongs to a business that is not yours. Build the booking page if you like. Do not build the till.
What actually breaks
not "if". the specific failures.
- Stored value, first. Packages, memberships, class credits and gift cards are balances, and a balance updated by read-modify-write is a balance two receptionists can spend at the same moment
- Coupons, because the table you generate has a code, a discount and an expiry, and the field that matters — how many times, per customer — is the one nobody asks for
- Refunds, which are not the payment path in reverse: partial amounts, a deposit already taken, a no-show fee the client disputes, and a processor fee you never get back either way
- Reminders at volume, where SMS costs real money per message and a retry loop is simultaneously a bill and a phone buzzing at 3am in somebody else's house
- Concurrency on the slot, because two people booking the same 09:00 on a Monday is the ordinary case for a salon, not an edge case
- Recurring availability across a DST change, per provider and per location, which is the bug that arrives twice a year and always looks like something else
- Intake answers, the moment a clinic uses it, when the free-text box quietly turns a booking row into a clinical note in a database with one backup and no retention policy
- Staff permissions, where the receptionist sees everything and the visiting contractor should see only their own column — a where-clause you will get right in nine endpoints out of ten
- Deletion, which has to reach the booking, the intake answers, the invoice, the SMS log, the calendar event and the processor's customer record, and which everybody writes last
The owner posts the promo code on Instagram the Thursday before a bank holiday: forty per cent off a five-session package, intended for the mailing list. There is no per-customer limit, because the coupon table you generated has a code, a percentage and an expiry, and the fourth field was never discussed. By Friday lunchtime the code is on a deals forum and your checkout is doing something it has never done before — working perfectly, six hundred times in ninety minutes. Each of those is a prepaid balance that obliges a two-chair salon to deliver five appointments at a price below the cost of the chair, held by people who have every right to turn up. The owner wants them cancelled, which means refunding six hundred card payments and eating six hundred processing fees the business never sees again. The ones you do not refund quickly enough come back as disputes instead, and the dispute rate is the number the payment processor actually watches. By Tuesday the salon's payouts are on hold, which is money it needed on Friday, and the bit you will keep replaying is that the field was optional because nobody said it should not be.
Is that you?
the verdict is a default, not a law
- It books your own time, for your own business, and payment is a hosted checkout link that never touches a server you own
- Nothing is prepaid: every visit is paid at the time, and no package, membership, credit or gift card exists in the schema
- The form collects a name, an email and which service — nothing anyone would describe as health, financial or legal information
- You self-host Cal.diy or Easy!Appointments and add the one field you actually needed rather than writing a booking platform
- You are building it for somebody else's business, which makes their clients' data your breach and their downtime your evening
- Any balance is stored — packages, memberships, class credits, gift cards, account credit from a cancelled visit
- A licensed practice will use it: physiotherapy, dentistry, counselling, anything with a registration number on the wall
- SMS or email reminders go out from your code and nobody has drawn what happens when the queue retries a batch
If you build it anyway
the checklist, then the prompt that enforces it
- Decide before the schema whether you are storing value. If a client can pay today for a visit next month, you need an append-only ledger with a computed balance, not a number two staff members can decrement at once.
- Hosted checkout only. A card form on a page you control drags the full PCI standard into a project that was meant to book haircuts, and there is no version of that which ends well.
- Every coupon has four fields, not three: code, discount, expiry, and a redemption limit both per customer and in total. Make the limit required and default it to something small.
- Refunds are money movement — idempotent, logged with who triggered them, and always reconciled against the processor's records rather than your own table.
- Put slot uniqueness in the database as a constraint on provider plus time range. Application-level checks lose the race that a Monday morning runs several times an hour.
- Keep intake answers in a separate encrypted store with their own retention clock and their own delete path, and never render them into an email, an SMS or a webhook payload.
- Cap every outbound channel: messages per client per day, total per hour, quiet hours in the client's timezone, and a kill switch that stops sending without needing a deploy.
- If a licensed professional will use it, get the HIPAA or equivalent question answered by somebody qualified before the first real client books. That answer changes the architecture, not the copy.
I am building an online booking system for a service business: several providers, deposits,
prepaid packages and reminders. Treat the money and the intake answers as the dangerous parts
and the calendar as the easy one. Build in this order and refuse the shortcuts.
1. Before any schema, ask whether clients can pay in advance for anything — packages,
memberships, gift cards, class credits. If yes, design an append-only ledger with a
computed balance, never a balance column updated in place.
2. Then ask whether a licensed professional will use this. If yes, say plainly that intake
answers are health information, that it changes hosting, logging, backups and contracts,
and that I should settle it before you write any tables.
3. Payments go through hosted checkout. Do not build a card form; if I ask for one, refuse and
explain what leaving the smallest PCI scope costs me.
4. Write the refund path in the same commit as the payment path: idempotent, logged with an
actor, reconciled against the processor, tested for partial and duplicate cases.
5. Coupons require a redemption limit per customer and in total. Make it a required field and
write the test where one code is used six hundred times in ninety minutes.
6. Enforce non-overlap with a database constraint on provider plus time range, then test two
clients booking the same slot concurrently.
7. Intake answers live in their own encrypted table behind their own accessor, and never appear
in an email body, an SMS, a webhook payload or a log line.
8. Build deletion before the booking UI: one call clears the booking, intake answers, invoice,
queued reminders, message log, calendar event and processor customer record. Assert it.
9. Reminders are sends — idempotent per booking and type, capped per client per day and per
hour globally, quiet hours in the client's timezone, plus a kill switch with no deploy.
10. Write the authorisation check once and apply it in every endpoint, then test that one
provider cannot read another provider's clients.
11. Compute availability from UTC instants plus an IANA timezone and test a weekly recurring
rule across both DST transitions before any booking page exists.
12. Out of scope unless I ask again: point of sale, tips, gift cards, memberships, classes,
multi-location and commission splits. Then finish by telling me what the vendor charges
and what it signs, so I can weigh that against holding prepaid balances myself.That one keeps you out of trouble. For the prompt that actually builds it, canivibecodeit.com has one.
their build prompt ↗Or don’t build it
the boring option, and the way back out
Any client outside your own head is booking, and certainly if there are prepaid balances or a licence on the wall. €29.90 a month buys a company that has already answered the deposit, refund, coupon-limit, reminder, timezone and retention questions, and that will sign a BAA if the practice needs one; the cheaper €13.90 tier covers payments and deposits if the compliance question genuinely does not apply. If it truly is just your own calendar, self-hosted Cal.diy is the cheaper honest answer and schedules better than you will.
$29.9/mo is cheaper than your weekend.
Keep the calendar and the payment processor as the systems of record and treat your database as an index over them: every confirmed appointment exists as a real calendar event, every charge and refund exists in the processor with a booking id in its metadata, and deleting your app costs the business its UI rather than its history. The two things that exist nowhere else are the intake answers and the ledger, so export both on a schedule — the ledger as entries rather than balances, so a successor system can recompute what each client is owed, and the intake answers encrypted with their consent state and retention date attached. And write down early who owns the client list, because when you hand this to the business or to a real vendor, that list is the only asset in the whole thing.
MIT community fork of Cal.com with booking pages, availability rules, payments and calendar sync; the sensible starting point if you insist on self-hosting.
Long-running open-source appointment scheduler built around providers, services and customer records — closer to a front desk than a booking link.
Questions
Acuity is already rated your funeral. What does this one add?
The counter. Acuity's page is about a client intake form and a card on file, which SimplyBook.me also has. What it adds is stored value and a shop: packages, memberships, class credits, gift cards, tips and a point of sale, sold to businesses with several providers and sometimes several locations. Prepaid balances are a different class of bug from a single charge — they are a liability sitting in your schema for months, they get spent concurrently by two people at a desk, and getting one wrong is an argument with a customer rather than a line in a log.
It is for a salon, not a clinic. Does the health part still apply?
Not directly, and you should score it honestly if it does not — a haircut booking is names, phone numbers and a card, which is a materially lighter build. Two things keep it on the page anyway. The free-text "anything we should know?" box collects whatever the client decides to type, including allergies and medication. And booking software gets lent: the version you wrote for a friend's salon is the version their physiotherapist neighbour asks for next, and nothing in the schema will stop that conversation.
What is the version of this I can actually build?
One provider, one location, pay-at-the-time only, a hosted checkout link for deposits, and a form that asks for a name, an email and a service. No packages, no gift cards, no memberships, no POS. That is a good weekend, every field on it is one you could explain to a stranger, and it stays reversible because nothing in it is a balance you owe somebody.
- 45 CFR Part 164 — HIPAA Security and Privacy Rules (US, eCFR)
- GDPR Art. 9 — processing of special categories of personal data (EU)
- PCI DSS standards library
- Stripe — reducing your PCI scope
Every week, someone ships something they shouldn’t have.
New verdicts, the worst thing that landed in the trap, and the occasional incident report. No other email, ever.
A booking form that asks “any conditions we should know about?” is a medical record with a submit button.
The double-booking isn't yours to apologise for. It's a stylist, at 9am, with two people booked into one chair.
A booking page fails loudly. A routing rule fails silently: the form says thanks and nobody is ever assigned.
last reviewed 2026-08-05 · verdict is editorial and unsponsored · shared entry data from canivibecodeit under MIT · not legal advice