Capability 14 · Booking & Reservation Systems

Booking & Reservation Systems

Calendars, availability and payments — with double-booking made impossible by design.

Before you read: Written from live engineering practice — the money-moving, million-user work our team runs on our own products, set down so anyone building something can learn from it.

01 · What it is

A booking system lives or dies on one promise: no two customers get the same slot. We build availability systems where the conflict is impossible by design — row-locked calendars, atomic booking logic and waitlists — not just by discipline. Clients and staff get dashboards that show reality in real time, deposits and holds move money correctly, refunds follow the right rules, and reminders chase no-shows before the empty chair costs you again. Rescheduling shifts records, not just the calendar.

What a booking & reservation systems build covers:

  • Real-time availability calendars with live state
  • Conflict-free booking logic enforced at the database level
  • Client & staff dashboards that show the same truth
  • Deposits, holds & refunds accounted correctly
  • Reminders & no-show follow-up flows
  • Rescheduling that keeps the accounting correct
What we do · How we do it — as TGJOF Enterprise

This is how we do Booking & Reservation Systems

Booking systems at TGJOF live or die on one guarantee: no two customers are ever promised the same slot. On top of that guarantee sits money — a deposit to hold a slot, a balance at the door, a refund when plans change — and every shilling has to move with the same exactness as the availability promise itself. We engineer capacity at the database level, wire deposits and holds into proper payment machinery, and make refunds follow policy rather than mood. The result is a calendar that cannot double-book and a ledger that still balances after the cancellations.

What we do

  • Availability that is a locked resource, not a hopeful query — slots and capacity rows are protected by the database itself, so two concurrent bookings on the same slot physically cannot both win.
  • Deposits and holds that behave like money — a deposit is captured and verified before the slot is promised, unpaid holds expire on a schedule, and escrow states are never ambiguous on screen or in logic.
  • Refunds that obey policy, applied exactly once — cancellation windows, forfeit fractions and same-rail returns are configured rules enforced by code, matched to the original transaction.
  • Payment at booking or at service, both first-class — take full payment, a deposit, or nothing until the door, and the same state machine carries each model while receipts tie every door payment to its booking.
  • The calendar and the ledger agree by construction — a booking, its money and the released slot move as one atomic fact, so the desk, the customer and the owner read the same truth.

How we do it

  • The check and the reserve are one transaction — the slot row is locked FOR UPDATE before the availability decision, so the window between 'is it free?' and 'it is yours' cannot be stolen.
  • Deposit rails are wired like any other money movement — a captured deposit is verified against its gateway before the booking confirms, and a retried request returns the same outcome instead of charging twice.
  • Holds are swept, not forgotten — scheduled jobs release unpaid reservations, hand off waitlists and run no-show policy under advisory locks, so a 'reserved' row cannot sit forever.
  • No-show charges and refunds carry proof — every fee and every return is a transaction with a reference and an audit row, so 'why was I charged?' has an instant, true answer.
  • The peak hour is load-tested as a contract — simultaneous doubles, callback replays and refund races are simulated in the build, because a calendar breaks exactly when the business is busiest.

02 · The full discipline

A booking system lives or dies on one promise: no two customers ever get the same slot.

Every booking system fails in the same two ways: a customer is told a slot is free when it is not, or two customers are told a slot is theirs at the same moment. The first is an inventory lie; the second is a concurrency failure. Both cost trust, and in Kenya the stakes are compounded because the booking is usually tied to money — a deposit via M-Pesa, a paid reservation, a no-show charge against a real wallet.

We build booking and reservation systems the way a payments studio has to, because KodiiPay is a live platform that moves real money on Safaricom's Daraja rails — STK pushes, deposits, holds, escrow, payroll-grade disbursements, idempotent callbacks and daily reconciliation. We bring that exact discipline to capacity: availability locked at the database level, double-booking made structurally impossible, deposits and refunds accounted to the shilling, and reminders that actually reach the customer in a market where SMS and WhatsApp are the real calendar.

Below is how we build booking systems that keep their promise — the availability engine, the row locks that make double-booking impossible, deposits and holds, payment-at-booking versus payment-at-service, no-show policies, reminders, waitlists and the honest limits of scheduling capacity.

03

A booking system is a promise about availability

Books can be sold twice and the customer can be given another copy. A haircut or a consultation that is doubled cannot be unbought — the chair was literally there once. A booking system therefore lives or dies on its single most important guarantee: at no moment, under no concurrency, does the same slot get promised to two people. Everything else is surface.

  • The promise is about capacity, not about records — the system manages slots, chairs, rooms, seats, vehicles and duty rosters, and every one of them can only be given away once.
  • Availability is the product — the calendar a customer sees is not decoration; it is the live inventory of what can still be promised.
  • The lock is at the database, not the app — two staff members clicking at the same moment are a normal event; the database physically prevents both from winning.
  • A booking that cannot be honoured is worse than no booking — the store or clinic handles the disgruntled walk-in; the platform must never create the disgruntled double-book in the first place.
  • Client and staff see the same truth — the customer's calendar and the reception desk's calendar are the same data, refreshed by the same write.
  • Money attaches to the guarantee — deposits, holds and no-show charges all hang off the availability promise, so the slot and the money move as one.

We have watched a naive booking module double-book a clinic and turn a paid customer into a shouting one. The architecture below makes that moment impossible by design, not polite by convention.

04

No two customers get the same slot

The naive way is to 'check availability' in the app and then create the booking — polite, and wrong, because between the check and the write another customer can seize the slot. The correct way is atomic: the check and the reservation happen in one locked operation, exactly like the check-and-move on a wallet:

  • Row locks make it impossible by design — the slot row is locked `FOR UPDATE` before the availability decision, so two concurrent bookings on the same slot physically cannot both succeed.
  • Atomic check-and-reserve — the availability check, the lock and the insert are one transaction; the system can never observe a state that was never true.
  • Capacity rows, not verbose queries — a room with capacity eight is one locked row; the service decrements it under lock rather than counting conflicting bookings in a query.
  • Versioned rows where locks are heavy — optimistic conditional updates refuse stale writes with a clean retry for surfaces that do not need a hard lock.
  • Partial availability is a first-class fact — half the room booked means half the room left; the lock understands units, not just booked-or-free.
  • The double-booking is tested, not assumed — the test suite fires two simultaneous bookings at the same slot and asserts one winner and one clean loser, every build.

A double-booking is not a UX bug; it is a contract violation with a complaining customer attached. We make the contract binding at the database level, and then we prove it with tests.

05

Real-time inventory of capacity

Beyond the single slot lies the shape of the whole calendar: rooms, staff, equipment, durations, buffer times and overrides. Inventory of capacity must behave like honest stock — it reflects reality, updates atomically, and is never optimistically generous:

  • The calendar is derived from capacity, not drawn — available windows are computed from the resource's true availability, breaks, buffers and existing bookings, so the grid is never a hopeful picture.
  • Durations, buffers and clean time are rules — a 45-minute session with a 15-minute buffer blocks an hour; the system understands that preparation is part of the slot.
  • Resources compose into availability — a booking that needs a room, a practitioner and a piece of equipment is only available when all three are.
  • Overrides are explicit and audited — a manual 'make this available' is a logged act with an actor, so someone can always explain how the calendar became what it is.
  • Open and close hours enforced — the system cannot sell a service outside operating windows, because the operating window is part of the resource definition.
  • Holiday and exception calendars — closures, maintenance and training days remove capacity before a customer ever sees it, not after they have paid.

A calendar that sells to capacity then cancels on reality is a calendar that burns trust. We build the inventory of capacity to match reality before the promise is drawn.

06

Deposits, holds and the money at booking

When the booking involves money — a deposit to hold a premium slot, a paid reservation, a rental advance — the booking machine becomes a payments machine. We run those flows on the same escrow and ledger discipline our own wallets run on:

  • Deposit captured on the customer's own rail — an STK push for the M-Pesa customer and a card charge or wallet capture for the one who pays that way; whatever the rail, the deposit is captured and verified before the slot is promised.
  • Payment at booking versus payment at service — some businesses take full payment now, some take a deposit now and the balance at the door, and some take nothing until service; the system supports all three models with the same state machine.
  • Escrow semantics — a deposit is held in an explicit state until service; it is consumed, released or reversed per policy, never ambiguous on screen or in logic.
  • Holds that expire — a held slot with an unpaid deposit expires on a schedule and returns to the shelf, so a 'reserved' row cannot sit forever while real customers are turned away.
  • The booking and the money move together — the reservation and its deposit ledger write atomically, so there is no moment where the slot is promised and the money is unaccounted.
  • Cancellation defined by policy, enforced by code — free-cancellation windows, forfeit rules and refund fractions are configurable and applied by the system, not negotiated by staff.
  • Shortfall handling with dignity — an insufficient balance or declined push returns the exact amount needed, and the hold protects the slot while the customer retries.

A booking whose money is uncertain is not really a booking. We wire deposits and holds into exact payment machinery so the slot and the shilling are one promise.

07

Deposits on whatever rail the customer pays from

For a Kenyan booking the deposit will usually arrive as an STK push, and that remains the lived core of any build here. Yet the same deposit desk meets Visa and Mastercard payers, PayPal and Stripe customers, PayStack where it is the local default, and businesses that prefer a direct bank transfer. We board every one of those rails into the booking's money machine — the same holds, the same verification, the same single-time refund — so the rail a customer chose can never weaken the promise the booking made:

  • The deposit state machine is rail-agnostic — a captured deposit is a captured deposit whether it landed via Daraja, a card processor, a wallet gateway or a bank transfer; the booking logic never special-cases by brand.
  • Per-rail verification before the slot is promised — STK Query proves the M-Pesa capture and signature and status checks prove the card and wallet rails; a deposit is confirmed to the booking only when the issuing rail says so.
  • Holds and expiries work across every collection type — an unpaid reservation expires on its schedule whether it was to be paid by card, wallet or bank, and the released slot returns to the shelf under the same lock.
  • Partial captures are exact across rails — a part-paid deposit, a half forfeit or a balance-at-door is computed from one amount table, so the fraction quoted to the customer reconciles whatever rail carried it.
  • Refunds return on the rail that took the money — card charges reverse with the card processor, wallet payments refund through the wallet gateway, and an M-Pesa deposit returns via B2C, each once and matched to the source.
  • Reconciliation totals every collection line — the day's deposits, door captures and refunds match their respective rail statements line by line, so the deposit pot balances even across five different ways of paying.

The rail is the customer's choice; the discipline is ours. We wire every collection route through the same honest machinery so a booking's promise — and its money — holds no matter how the customer pays.

08

Payment at service: the other model

Many Kenyan businesses — consultations, classes, short stays — take the booking free and collect money at service. That model is simpler but not without its own machinery: the booking still holds capacity, the no-show still costs, and the collection at the door still has to be captured, receipted and reconciled:

  • Book-free, pay-at-door confirmed as a flow — the reservation carries no money intent, but the service completion must capture the payment cleanly when it happens.
  • Collection at the point of service — the staff surface accepts M-Pesa via STK or Till and cards at the door, wired to the same ledger as the booking.
  • No-show policies still apply — a no-show on a free booking is a genuine loss; policies, waiting lists and deposit options exist to protect the revenue policy the business chose.
  • Receipts tie the payment to the booking — the door payment references the reservation, so 'did this booking pay?' reconstructs from one record.
  • Settlement is separated — deposits received in advance and collections at the door are distinct accounting lines that roll up into one honest daily reconcile.
  • Free bookings still need rate limits — an attacker booking every slot to sabotage a competitor is a real, structural concern; per-user limits apply to free reservations too.

The no-deposit model is a deliberate business choice, and we make it safe rather than naive. Book-free today, but the machine still knows who holds which slot and whether they paid.

09

Refunds, cancellations and policies that hold

Cancellation is where a booking system is tested hardest — the customer's willingness to book again, and the business's revenue policy, collide in one moment. A refund is a payment event and must obey the same rules as the deposit that created it:

  • Refund eligibility follows policy, not mood — cancellation windows, forfeit fractions and exception routes are configuration, enforced by the system, so staff never improvise.
  • The refund matches the original transaction — it carries the source booking and payment reference, is applied once, and a retried refund request returns 'already refunded' with its original outcome.
  • Money returns through the rail that carried it — a B2C disbursement returns the refund to the customer's M-Pesa, just as a card reversal or a wallet refund returns through that network, matched by reference and applied once.
  • Cancellation returns the slot atomically — the slot release and the refund ledger write in one transaction, so the system is never in a state where it has refunded and still holds.
  • Partial refunds are exact — a 50% forfeit on a deposit is computed from the real amount with the fee rules applied once, stated plainly to the customer.
  • Disputes leave a record — every cancellation, refund and exception carries actor, timestamp and reference, so 'what happened to my booking' reconstructs in minutes.

The refund flow is the deposit flow inverted, and it must be just as rigorous. We build it so a cancelled booking never becomes a burned relationship or a hole in the books.

10

No-shows: empty chairs are the enemy

A no-show costs a slot twice — the lost revenue and the customer who could have taken it. The machine cannot prevent every no-show, but it can surround the risk: policy, reminders and the waitlist re-cool the window so an empty chair is rare rather than inevitable:

  • No-show policy enforced by code — windows that forfeit a deposit and refund schedules that return it late are configured rules, applied identically every time.
  • Charge only when policy allows — a no-show fee is debited only through the explicit policy branch, never by a moody human and never silently against a wallet.
  • The record proves the charge — every no-show fee is a transaction with a reference, an audit row and a notification, so 'why was I charged' has an instant, true answer.
  • Reminder cadence reduces the event — well-timed SMS and push reminders measurably cut no-shows, and the cadence itself is configurable per business.
  • Waitlists fill the gap — a released or cancelled slot instantly offers itself to the next person waiting, shrinking the cost of every empty chair.
  • Rescheduling before the loss — a customer who cannot attend is given a cheap, honest path to move the slot, keeping the money and the relationship.

No-shows are a revenue leak we can shrink, not an act of God. Policy, reminders and the waitlist work together so the empty chair is the exception, not the routine.

11

Reminders that reach the customer

In Kenya the booking reminder competes with a life lived mostly on a phone — and the channels that actually reach people are SMS, WhatsApp and push, not an email that waits in a tab nobody opens. We engineer delivery the way delivery should be engineered: tracked, fallbacked and observable:

  • SMS as the reliable floor — short, plain and near-universal, the SMS reminder carries the date, time and cancel link; its delivery status is tracked, not assumed.
  • WhatsApp where the customer is — the business's WhatsApp Business presence meets the customer in the app they already live in, with the same message and a rich card.
  • Push with an in-app fallback — push notifications reaching the phone, with the in-app inbox as the guaranteed landing place when the OS denies the banner.
  • A tiered cascade — push first, SMS as the backstop, email as the permanent record; the system tries the next tier automatically when a channel fails.
  • Delivery receipts for compliance — proof of delivery per recipient, so 'the customer says they never saw it' is a question the records can answer.
  • Timing that respects the calendar — reminders arrive at hours that make sense for the service, on a cadence the business configures, never at midnight.
  • The cancel and reschedule reach through every message — every reminder carries an action, so the customer solves the problem in one tap instead of calling.

A reminder that vanishes into a silent channel is a reminder that might as well not exist. We engineer deliverability itself — and the customer hears, and you have proof they were reached.

12

Rescheduling that keeps the books right

Rescheduling is the most common request a booking desk receives, and the naive version is chaos: cancel here, rebook there, and the money state loses track of where it is. We treat a reschedule as what it is — one atomic move of the slot and the financial record together:

  • The new slot is reserved under the same lock discipline — the move books the new slot atomically, so the reschedule cannot itself double-book.
  • The old slot returns in the same transaction — the release of the old slot and the capture of the new one are one write, so capacity is never briefly 'lost'.
  • The money travels with the booking — a paid deposit moves to the new slot unchanged; a price difference generates an extra capture or a refund, never an ambiguity.
  • Policy still applies — rescheduling inside a forfeit window is governed by the same configured rules as cancellation, so the system never surprises either side.
  • Both parties are notified — the customer and the business each get a confirmation of the new time; nobody is left holding the old mental calendar.
  • The audit trail records the journey — every move is logged with actor and timestamp, so the lifetime of a booking reconstructs completely.

A reschedule is a goodwill moment that can easily become a financial mess. We make the slot move and the money move one single atomic fact.

13

Waitlists that take over when a slot opens

A waitlist turns refusal into relationship. The customer who could not get the slot is not sent away — they are told 'when it opens, you will know.' The machinery behind that promise has to be honest and automatic, not a human remembering to call:

  • Named, dated waitlist entries — each entry carries the customer, the service and the acceptable time window, so the offer only goes where it can be accepted.
  • Instant handoff on release — a cancellation or no-show release atomically hands the slot to the next eligible waitlist entry, under the same lock that protects all capacity.
  • Confirmation with a clock — the waitlisted customer is offered the slot with a short acceptance window; if they pass, the offer moves to the next entry while the slot still lives.
  • Waitlisted without paying — entry is free and consent-based; money only ever moves if the slot is accepted, at which point the deposit flow runs normally.
  • Offer via the reachable channel — SMS or WhatsApp carries the offer with a one-tap accept, so the person most likely to take the slot actually sees it.
  • Overlap resolution by policy — when two entries match one release, the policy is deterministic — earliest, most-overdue or manually prioritised — never a race in an innocent query.

The waitlist is the revenue the no-show would have cost. We build it so the empty chair has a person's name on it within seconds.

14

Client and staff see the same truth

The customer books on a phone; the front desk runs the same reality on a terminal; the owner watches it on a dashboard. If those three calendars can disagree, the desk becomes the place where promises break. We build one source of truth and surface it everywhere:

  • One booking record, many faces — the customer's view, the staff grid and the owner's dashboard read the same data; the write path is shared, so none can drift.
  • Real-time by construction — a booking made on the phone is visible on the staff terminal the instant it commits, not the next time someone refreshes.
  • Realtime alerts on the desk — new bookings, cancellations and no-shows surface to staff through the same notification machinery as the customer's confirmations.
  • Staff overrides are first-class events — the desk's manual changes are logged, reverseable and visible to the owner, so the human is never the invisible edit.
  • The owner's dashboard is the same truth at scale — utilisation, revenue per resource and no-show rates are aggregates of the one record, not reports re-keyed by hand.
  • Permissions on every surface — what each role can book, cancel or refund is enforced server-side, so the receptionist and the owner have different but honest reach.

Calendars that disagree are how promises get broken twice. We build one truth and let every surface argue against it if it wants — the record wins.

15

Concurrency at peak hour

Friday evening at a salon, a clinic's Monday morning, a hotel's December — the moment everyone calls at once is exactly when the system must be most honest. The same concurrency discipline that protects money on our own platform protects the calendar:

  • Row locks around every check-and-reserve — the slot row is locked `FOR UPDATE` so two requests racing for the same opening cannot both win, at any load.
  • Advisory locks on capacity sweeps — expiry, release and waitlist jobs claim locks and use SKIP LOCKED, so overlapping job runs cannot double-hand slots.
  • Terminal-state protection — a booking already cancelled, refunded or completed is matched and answered, never re-opened, no matter how many threads reach it.
  • Idempotency keys on the booking request — a panicked double-tap or a network retry produces one booking, not two; the duplicate returns 'already booked'.
  • Dead-letter honesty — payment captures or reminder sends that keep failing rest visibly with their payload, so neither a booking nor its money is silently lost.
  • Proven under the peak you expect — we test the booking path at the simultaneous load of a real peak hour, not the load that fit on a slide.

Concurrency bugs on calendars reproduce exactly when the business is busiest and most embarrassed. We engineer them out of the architecture and prove it with tests that simulate the exact peak.

16

Idempotency: the retry is a friend, the duplicate is the enemy

A customer on a shaky connection taps 'book' twice. A payment callback arrives twice. A reminder job and a human both try to contact the same waitlist entry. Without idempotency, every one of those is a second booking, a double charge or a double message. Idempotency is the personality of the booking record itself:

  • A unique reference born at request — the booking request carries a reference that is its identity; the same reference replayed returns the same outcome, never a second booking.
  • Idempotent confirmations — replaying a payment confirmation callback credits and confirms exactly once; the second arrival returns the settled state.
  • Idempotent refunds — a refund references its source booking and applies once; a retried refund request answers 'already refunded' with the original result.
  • Idempotent reminders — a reminder job that runs twice sends one message; the deduplication window is part of the job, not a hope.
  • Idempotent no-show charges — a no-show fee is born once per window with one reference; a re-run of the policy job cannot double-charge.
  • Idempotency is tested, not assumed — the suite re-delivers every callback and re-sends every request and asserts the records changed exactly once.

Your customer's network may hiccup, the gateway may redeliver and your staff may double-click. All of that is survivable when the booking remembers itself. Ours do.

17

Rate limits and abuse protection

A booking calendar is a real business asset, which means it is also a target: a competitor books every slot then cancels, a bot scraper hammers availability, an attacker floods paid deposits. Abuse is structural, and the controls are structural:

  • Per-user, per-action rate limits — 5-second budgets on booking, cancelling and deposit paths, at the gateway and inside logic, so no CDN bypass can dodge them.
  • Booking velocity limits — per-account booking and cancellation ceilings flag or block the pattern of promise-then-cancel that wastes real inventory.
  • Deposit limits with identity — high-value deposits, unusual velocity or new-account bursts trigger holds and identity gates rather than blind acceptance.
  • Enumeration resistance — availability responses are uniform whether a slot is genuinely free or exactly reserved, so scraping cannot map the calendar.
  • Suspicious patterns surfaced — the same device, the same number, a burst of accounts — flagged to the operator with evidence rather than silence.
  • Holds with a human path back — a flagged account is held with a clear, owner-informed recovery instead of locked with no door.

The legitimate customer books one slot in under a minute with zero friction; the abuser meets a wall at every route. Structural rules, not hoping.

18

Reconciliation: bookings to money, every day

A clinic that takes deposits by STK, collects balances at the door and processes refunds weekly has decided, by the end of each day, whether its deposit pot matches its statement. That decision must not be a spreadsheet ritual:

  • Match deposits by gateway reference — every STK capture is matched to its booking by the transaction's reference, line by line, not by amount-and-date guessing.
  • Total bookings versus money — the day's expected captures from bookings reconcile against the M-Pesa statement; a mismatch is an incident with an investigation.
  • Drill to the discrepancy — when totals disagree, the system isolates the specific booking and transaction, so 'which one is this?' has an answer fast.
  • Scheduled and unattended — a cron job runs the reconcile, flags exceptions and pages the right person instead of waiting for a human to remember.
  • Deposit versus at-door settlement stays distinct — advances and door collections are separate lines that roll into one honest daily total.
  • Refunds reconcile too — money out is matched to its source capture, so the discount the refund books is exactly the deposit that returned.

The deposit pot is not a hope; it is a number that must prove itself daily. We build the proof as a system from the first sprint.

19

How we build booking systems

The process is the same from a one-chair salon to a national operator. It is staged, honest and delivered in increments a business can absorb:

  • 01 · The capacity audit — map every resource, slot shape, duration and money rule in the current operation, and find where double-booking or lost revenue live today.
  • 02 · The availability model — resources, durations, buffers, capacity and operating hours specified as the ground truth the calendar derives from.
  • 03 · The lock design — slot and capacity rows, FOR UPDATE discipline and atomic check-and-reserve specified before any screen is drawn.
  • 04 · The money design — deposits, holds, at-door payment and refund rules set against real payment rails with precise fee and forfeit arithmetic.
  • 05 · The payment wiring — STK captures, verifications and refunds rehearsed against genuine gateway callbacks, with failure drills.
  • 06 · The reminder cascade — SMS, WhatsApp and push delivery wired and tracked, with channel fallbacks configured per business.
  • 07 · The waitlist machinery — named entries, instant handoff and confirmation clocks built the same week as the core booking.
  • 08 · The surfaces — customer booking, staff grid and owner dashboard wired to the one record with server-side permissions.
  • 09 · The tests — simultaneous doubles, peak-hour races, callback replays, no-show charges and refund paths simulated as part of the build.
  • 10 · The ops — monitoring on booking and money paths, expiry sweeps, support logs and the 'why was I charged' answer path.
  • 11 · The growth — more locations, more service types, more volume — added to the same architecture, never as a bolt-on that breaks the promise.

You own the calendar data, the ledger, the code and every gateway key. No hostageware — the booking machinery is yours.

20

Honesty about booking systems

Because a booking is a promise and money is attached, we are direct about the trade-offs — the ones a vendor who wants the logo would never mention:

  • No software removes every no-show — the machine can remind, hold and waitlist, but a genuinely idle chair at a booked time is part of running capacity; policy is your lever, code is your enforcement.
  • Deposit policies shape demand — a business that takes no deposits will see more no-shows; we build whatever policy you choose, but we tell you honestly what it will cost.
  • Multi-resource availability is genuinely complex — staff, equipment and room all needed at once creates real combinatorial availability; the simple grid is often a lie in disguise.
  • Refunds are infrastructure, not a menu item — the refund path is as important as the booking path and must obey the same discipline; it cannot be attached as an afterthought.
  • Sandbox is not production — a booking that verified in a sandbox but skipped the payment-verification loop will charge a real customer wrongly; the truth is in the statement.
  • The promise is tested at peak — a calendar that works in a demo and breaks at 9am Monday is a calendar that was never honestly load-tested.
  • You own it all — the data, the calendar, the ledger and the keys; nothing your customers trusted should be hostage to a vendor relationship.

We will tell you honestly when a business does not need the full capability — and give the smallest correct build. And when it does, this is what a booking system that keeps its promise looks like.

The toolchain

The booking & reservation toolchain

This is the stack that makes a double-booking structurally impossible and a deposit accounted to the shilling — built the way a live payments platform builds its machinery.

stack.toolchain

01

Inventory & availability engine

The ground truth of capacity

  • Capacity data modelResources, slots, durations, buffers and capacity composed into the true availability a calendar derives from.
  • Row-level lockingFOR UPDATE on slot and capacity rows so the check-and-reserve is atomic and double-booking is impossible.
  • Versioned optimistic rowsConditional updates refuse stale writes with a clean retry where a hard lock is overkill.
  • Open/close & exception calendarsOperating windows, holidays and maintenance removing capacity before a customer ever sees it.
  • Multi-resource compositionAvailability only when room, staff and equipment are all free, evaluated under the same lock.
  • Partial-capacity unitsUnits, not just booked-or-free, so half a room still means half the room is honestly left.

02

Booking & reservation logic

The promise, made exactly once

  • Atomic check-and-reserveAvailability check, lock and insert in one transaction; the system never observes an impossible state.
  • Idempotency keysThe reference born at request; replays answered, never re-booked, never double-charged.
  • Terminal-state matchingCancelled, refunded or completed bookings are matched and answered, never re-opened.
  • Reschedule engineNew-slot capture and old-slot release as one atomic move, with money travelling with the booking.
  • Waitlist machineryNamed entries with instant, clocked handoff to the next eligible customer on every release.
  • No-show & policy engineWindows, forfeits and refund schedules as configured rules, enforced identically by code.

03

Payments & deposits

Where the slot meets the money

  • Daraja (M-Pesa)STK Push deposits, at-door captures, B2C refunds and B2B settlements on the real rails.
  • Carls railsCard capture for deposits and balances alongside M-Pesa in the same state machine.
  • Escrow semanticsDeposits held, consumed, released or reversed in explicit states, never ambiguous.
  • STK Query / verificationThe status API proving a deposit or capture is genuine before a booking is confirmed.
  • Fee & forfeit arithmeticDeposit fractions, forfeits and refund amounts from one exact function, stated before money moves.
  • Payment state machineInitiated → pending → confirmed/failed/refunded with terminal-state protection.

04

Communications & reminders

Reaching the booker reliably

  • SMS deliveryThe reliable floor that carries date, time and cancel link to a near-universal reach.
  • WhatsApp BusinessRich reminders and one-tap actions inside the app the customer already lives in.
  • Push with in-app inboxBanner push with the guaranteed fallback landing place when the OS denies the banner.
  • Tiered cascadePush → SMS → email fallback triggered automatically when a channel fails, with visible status.
  • Delivery receiptsPer-recipient proof of delivery for compliance and dispute resolution.
  • Cadence configurationReminder timing and frequency set per business, respecting sensible hours and consent.

05

Ledger & financials

Bookings reconciled to the shilling

  • Double-entry booking ledgerDeposits, captures, forfeits and refunds as immutable journal rows with references and audit.
  • Reconciliation engineCaptures matched by gateway reference and totalled against the statement daily.
  • Scheduled sweepsExpire unpaid holds, release stale reservations, hand off waitlists and run no-show policy.
  • Advisory locks on money cronsOverlapping job runs cannot double-charge, double-refund or double-notify.
  • Revenue per resourceUtilisation and revenue per staff, room or service as aggregates of the one truth.
  • Three-layer money protectionPre-flight check, atomic write and a CHECK constraint on every affected balance.

06

Calendar & scheduling surfaces

One truth, many faces

  • Customer booking flowThe availability calendar, booking and payment on the phone, honest to the live lock.
  • Staff gridThe reception desk's real-time grid fed by the same writes, with logged overrides.
  • Owner dashboardUtilisation, revenue and no-show rates drawn from the one record.
  • Server-side permissionsWhat each role can book, cancel or refund enforced by the backend, not the button.
  • Real-time desk alertsNew bookings, cancellations and no-shows surfacing through the notification machinery.
  • Receipt & confirmation surfacesBooking confirmations and payment receipts correct, searchable and permanent.

07

Operations & observability

Running the calendar while you sleep

  • Rate limitingPer-user, per-action windows on booking, cancelling and deposit paths at gateway and logic.
  • Abuse detectionBooking velocity, scraping resistance and burst patterns surfaced with evidence.
  • Payment gateway logsRaw callbacks and verification results queryable by support and reconciliation.
  • Monitoring & budgetsLatency and error budgets on the book, pay and notify paths with timelines.
  • Dead-letter queuesFailed captures, sends or handoffs rest visibly with their payload, never silently lost.
  • Incident runbooks'Why was I charged and where is my slot' answered in minutes from the record and the log.

Lifecycle

The booking lifecycle — from capacity audit to scale

Every booking system we build passes through the same arc, from the first map of the real calendar to the operated promise. The deposits and locks are part of the build from week one.

01

Audit capacity

Map every resource, slot shape, duration and money rule in the operation; find where double-booking and lost revenue already live.

02

Model availability

Resources, durations, buffers, capacity and operating hours defined as the ground truth the calendar derives from.

03

Design the locks

Slot and capacity row discipline, FOR UPDATE and atomic check-and-reserve specified before screens.

04

Set the money rules

Deposits, holds, at-door payment and refunds set against real rails with exact forfeit and fee arithmetic.

05

Wire the payments

STK captures, verifications and refunds rehearsed against genuine callbacks with failure drills.

06

Build the reminder cascade

SMS, WhatsApp and push delivery wired and tracked with automatic channel fallbacks.

07

Build the waitlist

Named entries, instant handoff and confirmation clocks built with the core booking.

08

Connect the surfaces

Customer flow, staff grid and owner dashboard wired to the one record.

09

Rehearse failure

Simultaneous doubles, peak races, callback replays, no-show charges, refunds — simulated in the build.

10

Operate

Monitoring on booking and money paths, expiry sweeps, support logs, incident runbooks.

11

Reconcile daily

Deposits matched by reference and totalled against the statement; anomalies surfaced, never silent.

12

Grow

More locations, service types and volume — added to the architecture, never as a bolt-on.

Closing

More than development

A booking system is a promise about capacity, a payments machine, and a reminder service — built to the standard of a live money platform. That includes:

A real-time inventory of capacity that the calendar derives from.Row-level locks that make double-booking structurally impossible.Atomic check-and-reserve so no race can produce two winners.Deposits and holds via STK with escrow semantics, exactly accounted.Payment at booking and payment at service as first-class models.Refunds that follow policy and return money on the same rail, exactly once.No-show charges that fire only when policy allows, with proof.SMS, WhatsApp and push reminders with tiered fallbacks and receipts.Cancellations and reschedules that move slot and money atomically.Waitlists that hand off released capacity within seconds.Client, staff and owner sharing one non-disagreeing truth.Idempotent bookings, refunds, charges and reminders, tested not assumed.Rate limits on every booking and deposit path.Structural abuse protection against calendar-jacking and scraping.Daily reconciliation of deposits against the M-Pesa statement.The promise stress-tested at the peak hour the business actually sees.Fee and forfeit arithmetic exact and shown before money moves.Audit trails that reconstruct any booking's lifetime in minutes.The discipline run live on our own payments platform.You own the calendar, the ledger, the data and the keys.

A booking platform is judged on the one violation it never makes: promising the same moment to two people. Everything above exists to make that violation impossible.

We run payment machinery like this every day. When your calendar needs to keep its promise, you get the discipline that survived being live — not the one that survived only a demo.

Previous capability

E-commerce

Next capability

Communication Systems

Building something like this?

The discipline above is what we run on our own products every day. If it would help on yours, our door is open.