Part 1 of 7 · Booking deposit collector series ~10 min read

A booking deposit collector on AWS for a few dollars a month

A no-show costs an appointment business twice: the slot sat empty and it was too late to fill. This post walks through the design of a small serverless system that asks for a deposit the moment a booking is made — holding the slot, sending one payment link, confirming the payment exactly once, and quietly freeing the slot if the deposit never comes.

Key takeaways

  • A booking fires an event; within seconds the slot is held PENDING and the customer gets one message with a deposit link.
  • When the deposit clears, the payment provider’s signature-verified webhook flips the booking to CONFIRMED — exactly once.
  • If the deposit isn’t paid by a deadline, a scheduled sweep releases the hold so the slot is free to re-sell.
  • One Bedrock call phrases each message in your voice. Every decision — the hold, the confirm, the release — is plain Python.
  • Designed on AWS for about $2.40/month at roughly 120 bookings. It holds a slot once, reminds once, and never double-books.

The whole system on one page

Before any code, here’s the shape of what we’re designing. Every business that runs on appointments — a tattoo studio, a fine-dining restaurant, a dog groomer — loses money to the same quiet failure: the slot was booked, nobody turned up, and by the time anyone noticed it was far too late to sell it to somebody else. A deposit fixes it, but only if it’s asked for at the right moment and chased without nagging. The system below does exactly that: a booking comes in, the slot is held, a deposit link goes out, and the calendar stays honest whether or not the money arrives.

System architecture: a booking in, a payment provider and the customer around it, five pieces inside AWS At the top, three external boxes in a row. Far left, “Booking source” — the form, phone call, or walk-in that creates a booking and posts it to AWS. Centre, “Customer” — the person who receives the deposit-request message and taps the link to pay. Far right, “Payment provider” — the hosted checkout that takes the deposit and fires a webhook the instant it clears. Each connects by an arrow to the AWS account container below. The booking source sends the booking in; the customer receives the deposit link and pays; the payment provider posts the confirming webhook. Inside the AWS account are five components. Top-left, Hold the slot — receives the booking, writes a PENDING hold on that exact slot with a conditional write so it can never be sold twice, and sets a deposit deadline. Next, Request deposit — one Bedrock Haiku call phrases a friendly message and code injects the payment link, sent to the customer. Top-right, Confirm payment — the payment webhook on its own Function URL, verified by signature and made idempotent, which flips the booking to CONFIRMED exactly once. Below sit two more. Release or remind — a scheduled sweep that reminds once before the deadline and, if the deposit is still unpaid, releases the hold so the slot is free again. Settle on the day — the confirmed deposit is applied to the bill for a customer who turns up, or forfeited for a no-show, per policy. Arrows flow from hold to request to confirm, with the sweep and settle branching below. A note at the bottom reads: one slot, one hold — pay and it’s confirmed, ignore it and the sweep frees the slot; it never double-books. Booking source form, phone, walk-in Customer gets link, taps to pay Payment provider hosted link + webhook booking in deposit link out paid webhook AWS account Hold the slot PENDING, one slot, deposit deadline Request deposit one Bedrock call, payment link injected Confirm payment webhook, signed, idempotent → CONFIRMED ask paid Release or remind scheduled sweep, free the slot if unpaid Settle on the day apply to bill, or forfeit on no-show unpaid on the day One slot, one hold — pay and it’s confirmed, ignore it and the sweep frees the slot; it never double-books.
Fig 1. Three things outside, five pieces inside AWS. A booking comes in and Hold the slot places a PENDING hold; Request deposit sends one payment link; Confirm payment flips the booking to CONFIRMED when the webhook arrives. Release or remind frees an unpaid slot, and Settle on the day applies or forfeits the deposit.

What you set up once (the outside)

  • A booking source. Wherever bookings already come from — your website’s booking form, a reservation widget, or a member of staff typing one in from a phone call. It needs to do one thing: post the booking (who, when, which table or chair or slot) to one AWS URL. This is the trigger for everything, and it’s covered in Part 2. You don’t replace your booking flow; you tap into the moment a booking is created.
  • A payment provider. A hosted checkout — Stripe, or similar — that can take a small deposit on a card and, crucially, fire a webhook the instant the payment clears. You never touch card details; the provider hosts the payment page, and your system only ever sees a signed “this deposit was paid” message. Its signing secret and API key live in Secrets Manager. This is Part 3, and it’s where the money-handling care goes.
  • Your voice, your policy, and a place for handovers. A small settings doc holds the business name and tone for the messages, the deposit amount and deadline, the quiet hours, and the no-show policy — whether a deposit is applied to the final bill, held against the table, or forfeited. Alongside it, an address (an inbox or a shared queue) where the system drops anything a person needs to handle: a disputed forfeit, a failed payment, an odd booking. The system decides the routine cases; a human owns the exceptions.

What runs on every booking (the inside)

  • Hold the slot. The booking source posts to one Lambda Function URL. The function writes a PENDING hold on that exact slot with a conditional write — so a second booking for the same slot can never take it — and stamps a deposit deadline on the record. Only a genuinely free slot gets held. This is Part 2.
  • Request deposit. One Bedrock Haiku 4.5 call takes the handful of facts it’s allowed — the customer’s name, the slot, the deposit amount — and phrases a single warm message. Code injects the real payment link afterwards, so it can never be mangled, and sends it. This is the end of Part 2.
  • Confirm payment. When the deposit clears, the payment provider posts to a second Function URL. The function verifies the signature, then flips the booking from PENDING to CONFIRMED with a conditional write — so even if the same event arrives twice, the booking is confirmed exactly once. This is Part 3.
  • Release or remind. A scheduled sweep sends one reminder before the deadline and, if the deposit is still unpaid when the deadline passes, releases the hold so the slot returns to sale. Each booking is reminded once and released once. This is Part 4.
  • Settle on the day. For a confirmed booking, the deposit is applied to the final bill if the customer turns up, or forfeited if they don’t — decided by the policy, recorded, and handed to a person for any dispute. This is Part 5.

In plain words

It’s Tuesday and a table for six books online at The Copper Table for Saturday at 8pm — their busiest, most over-subscribed slot. The booking hits the system, which writes a PENDING hold on that table and time so no one else can grab it, and within about ten seconds the customer’s phone buzzes: “Thanks for booking with The Copper Table, Marcus! To hold your table for six on Saturday, we ask for a £30 deposit — it comes straight off your bill on the night. Pay here: coppertable.uk/d/7f3a.” He taps, pays with Apple Pay, and the provider’s webhook lands a second later. The booking flips to CONFIRMED, the table is locked in, and nobody at the restaurant lifted a finger.

Two doors down, a different table books the same Saturday but never pays. The reminder goes out the next morning — “just a nudge, your table’s held until 6pm today” — and still nothing. At 6pm the sweep runs, sees the deadline has passed with the deposit unpaid, and releases the hold. The 8pm Saturday table is back on the booking page within the minute, ready for someone who’ll actually turn up. No awkward phone call, no table sitting empty on the busiest night of the week. The deposit did its job by never being paid: it filtered out the booking that was never real.

Design rules that shaped every decision

  • One slot, one hold. A conditional write on the slot means a booking is held once and never double-booked, however many requests arrive.
  • One payment, one confirmation. The webhook is idempotent — the same event delivered twice still confirms the booking exactly once.
  • Verify before you trust money. The payment webhook’s signature is checked before a booking is ever moved to confirmed.
  • An unpaid hold always expires. A slot is never held forever; the sweep reminds once, then releases it so it can be re-sold.
  • The model only writes words. The hold, the confirm, the release, and the settlement are deterministic; Bedrock just phrases the messages.
  • Policy decides, a person handles disputes. Apply-or-forfeit is a plain rule; anything contested goes to a human with the full record.

Why this shape

Most appointment businesses handle no-shows one of three ways: they eat the loss and grumble, they take a deposit by hand over the phone (slow, awkward, and easy to forget), or they buy into a heavy booking platform that bundles deposits with a monthly fee and a cut of every transaction. The first is the real cost — a busy Saturday with two no-shows can wipe out a night’s margin. The second doesn’t scale past a handful of bookings a day. The third works but is expensive and takes over your whole front-of-house. The gap is a light-touch collector that clips onto the booking flow you already have and asks for a deposit the instant a booking lands.

The shape above fills exactly that gap and nothing more. It leans on the payment provider you’d use anyway to actually move the money, keeps your booking flow where it is, and adds a small system that holds the slot, asks once, chases once, and frees the slot if the answer is silence. The common case — a real customer who pays — is a tap on a link and a confirmed table. The few that never intended to come are quietly filtered out before they cost you the slot, and the genuinely awkward cases (a disputed forfeit, a failed card) are handed to a person with the whole story attached.

The next four posts walk through each piece in turn: how a booking becomes a held slot and a deposit request, how a paid deposit gets confirmed, how an unpaid hold gets released, and how a no-show gets settled. One diagram per post. A cost breakdown and a final engineering reference at the end.

All posts