Series · 7 parts Published May 1, 2026

Booking assistant

A serverless booking assistant on AWS that reads appointment requests, checks Google Calendar, proposes slots that respect your service rules, locks in the customer’s pick, and sends quiet reminders. Seven posts on the same system — one diagram at a time — with an engineering reference at the end.

  1. 01

    A booking assistant on AWS for a few dollars a month

    The whole system on one page — a reader, a scheduler, a confirmer, and the four moves they share for every inbound request.

  2. 02

    How a booking request reaches the assistant

    Three lanes at the door: web-form fast path for the easy 80%, AI-handle for free-text email, direct escalate for VIPs the AI should never touch.

  3. 03

    How the assistant understands the request

    Three small extractors run in parallel: which service, when roughly, and who’s booking. Confidence on every field; anything borderline becomes a draft.

  4. 04

    How the assistant picks slots

    Five filters in order: calendar query, working hours, duration plus buffers, blackouts and capacity, then rank. Every constraint comes from your rules file.

  5. 05

    How a booking gets confirmed

    Claim, write, confirm, remind — in that order. An atomic claim row prevents double-booking even when two customers click at the same second.

  6. 06

    What the booking assistant costs

    A coffee a month at SMB volume. Cents per request, scaling with the email lane — the form lane is essentially free.

  7. 07

    Engineering reference: the booking assistant architecture

    Same system, drawn purely for engineers. Service names, resource identifiers, region, Bedrock model IDs, Google Calendar API choices.

What does the booking assistant do?
It reads booking requests from a web form or your existing email address, parses fuzzy text like “next Tuesday afternoon for a haircut” into a structured request, queries your Google Calendar for free time, applies your service rules (durations, buffers, working hours, blackouts, capacity), proposes 2–3 viable slots, and on the customer’s pick claims the slot atomically, writes the calendar event, sends a confirmation with an .ics file and signed reschedule/cancel links, and schedules quiet reminders the day before and an hour before.
How much does it cost to run?
About $3/month at typical small-business volume (around 200 booking requests/month). The fixed cost is essentially zero — Lambda, S3, DynamoDB, EventBridge, and CloudWatch sit in or near the always-free tier. Variable cost is per-request pennies: SES inbound and outbound at $0.10 per 1,000 emails, plus Bedrock Haiku tokens (~$0.001 per parsed email-lane request). The web-form lane skips the AI entirely. Most setups land between $1 and $5 a month total.
Which calendar systems does it support?
Google Calendar is the primary target — the assistant uses Google Calendar v3 freebusy.query for availability and events.insert for confirmed bookings, authenticated via a service account with domain-wide delegation. Microsoft 365 swaps in cleanly if you’re on Outlook/Exchange: replace the Google Calendar v3 calls with Microsoft Graph getSchedule and events.create. Same shape, different SDK, same atomic-claim and stable-event-id idempotency story.
How does it avoid double-booking?
An atomic claim step before the calendar write. A small DynamoDB table tbl-claims is keyed by (resource_id, slot_start_iso). The confirmer does a PutItem with ConditionExpression: attribute_not_exists(resource_id). The first request for a given slot wins; any second request gets a ConditionalCheckFailedException and is bounced back to the proposal stage with fresh slots. The calendar event itself is written with a stable UUID set as the event id, so a retried write returns 409 duplicate instead of creating a second event.
How does it know my service rules?
A single rules.yml file in a Drive folder holds your service catalogue (durations, prices, qualified resources, aliases), working hours per resource, buffer times, blackout dates, capacity caps, ranking preferences, and confirmation tone. A small fn-config-sync Lambda mirrors the file to S3 on Drive changes.watch notifications, chunks and embeds the catalogue with Bedrock Titan Embeddings v2, and writes vectors to an S3 Vectors index named vec-services. Editing the doc updates the assistant’s behaviour without a deploy.
What happens for VIPs or edge cases?
Three lanes at the door before any AI runs. Lane 1 (web-form fast path) skips the parser entirely when the form is filled in cleanly. Lane 2 (AI handle) runs the parser on free-text email and partial form notes. Lane 3 (direct escalate) forwards anything from a sender on the allowlist — regulars, partners, first-time VIPs — straight to your normal inbox with an X-Assistant-Lane: direct header, untouched by the AI. Anything the parser sees with low confidence becomes a one-screen draft you approve before the assistant carries on.
Which AWS services does it use?
Lambda (with Function URLs for the form intake and confirmer), DynamoDB on-demand (tbl-requests, tbl-claims, tbl-audit), S3, EventBridge Scheduler (one-time schedules for reminders), SES inbound and outbound, Secrets Manager (the Google service-account key), CloudWatch Logs with seven-day retention, AWS Budgets, and Bedrock (Claude Haiku 4.5 via Global cross-Region inference, plus Titan Text Embeddings v2 with an S3 Vectors index for the service catalogue). No API Gateway, no NAT Gateway, no always-on compute.
All posts