Part 1 of 7 · Missed-call text-back series ~10 min read

A missed-call text-back on AWS for a few dollars a month

A missed call is the quietest way a small business loses a customer: the phone rings out, the caller hangs up, and more often than not they ring the next shop down the list. This post walks through the design of a small serverless system that turns that missed call into an instant, friendly text back — matched to the caller, with a booking link — and quietly hands the hard ones to a person.

Key takeaways

  • A missed call fires a webhook from your telephony provider; within seconds the caller gets one friendly text back.
  • The caller’s number is matched to any known customer or order, so the text can use their name and the right booking link.
  • One Bedrock call writes the wording in your voice. Everything else — the trigger, the match, the routing — is plain Python.
  • It sends exactly one text per missed call, honours quiet hours and STOP, and never cold-texts or chases.
  • Designed on AWS for about $2.20/month at roughly 150 missed calls a month. It only ever texts back — a human handles the rest.

The whole system on one page

Before any code, here’s the shape of what we’re designing. Every small business that takes calls misses some of them — the till is busy, it’s after hours, both lines are engaged — and a missed call is almost invisible. There’s no voicemail half the time, no record anyone looks at, and the caller simply rings the next shop down the list. The system below catches that moment and turns it into a conversation: a missed call comes in, and a friendly text goes back out, matched to the caller, within seconds.

System architecture: a missed call in from the provider, customer records and your team around it, four pieces inside AWS At the top, three external boxes in a row. Far left, “Telephony / SMS provider” — the phone system that fires a missed-call webhook when a call goes unanswered and carries the text-back and any reply. Centre, “Customer records & booking” — a Google Drive sheet with one row per customer or order (name, phone, last visit, notes) mirrored into AWS, plus the booking link and FAQ the text points to. Far right, “Your team” — the person who picks up anything the system won’t handle automatically. Each connects by an arrow to the AWS account container below. The provider sends the missed-call event in and receives the outgoing text. Customer records ground every match and supply the booking link. Your team receives escalations. Inside the AWS account are four components. Left, Catch and match — receives the webhook, verifies it, collapses repeat rings to one, checks quiet hours and STOP opt-out, and matches the caller’s number to a known customer. Next, Compose text-back — one Bedrock Haiku call that is handed only the facts it may use and writes a single friendly SMS with the booking link, sent back out through the provider. Next, Route replies — takes any inbound reply, threads it to the right person or queue, and answers nothing on its own. Below the middle sits Escalate — anything unmatched, anything urgent, and any text-back that goes unanswered after a set window is routed here to a person, fed both by the live path and by a scheduled no-reply sweep. Arrows flow left to right through catch, compose, and route, with branches down into escalate. A note at the bottom reads: it sends exactly one text per missed call, honours quiet hours and STOP, and a human handles everything it won’t. Telephony / SMS missed-call & reply webhooks Records & booking Drive sheet, booking link Your team where escalations land missed call in, text back out grounds escalation with context AWS account Catch & match verify, dedup, opt-out, match the caller Compose text-back one Bedrock call, one SMS + booking link Route replies thread to the right person or queue send reply Escalate to a person, with context no match urgent reply no reply (sweep) It sends exactly one text per missed call, honours quiet hours and STOP, and a human handles everything it won’t.
Fig 1. Three things outside, four pieces inside AWS. A missed call comes in from the provider; Catch & match decides whether to reply and to whom, Compose sends one text-back with a booking link, and Route threads any reply to a person. Anything unmatched, urgent, or unanswered branches to Escalate.

What you set up once (the outside)

  • Telephony and SMS provider. Whatever already carries your business number — a VoIP or cloud-phone provider that can do two things: fire a webhook the moment a call goes unanswered, and send and receive SMS on that same number. The missed-call webhook is the trigger for everything; the SMS side is how the text-back goes out and how replies come back. You point the provider’s webhook at one AWS URL and store its keys in Secrets Manager. This is the only moving part you don’t own, and it’s covered in Part 2.
  • Customer records and a booking link. A Google Sheet in a Drive folder with one row per customer or recent order: name, phone, last visit or order, and a note or two. You already keep something like this; this just puts it where the system can read it, so a text can open with the caller’s name instead of “Hi there”. Alongside it sits the one thing every text points to — your booking link (or a short FAQ page) — and a small settings doc for the voice, the opening hours that define “quiet”, and the escalation rules.
  • Your team. The person who picks up everything the system deliberately won’t handle on its own — usually whoever answers the phone. They get a message (email, or a row in a shared inbox) with the caller’s number, the customer it was matched to, the text that went out, and the reply so far. The system never books, quotes, cancels, or promises anything; it opens the conversation and a human carries it on.

What runs on every missed call (the inside)

  • Catch and match. The provider posts a missed-call event to one Lambda Function URL. The function verifies the signature, collapses repeat rings from the same number into a single job, checks the number against the STOP opt-out list and the current quiet hours, and matches the caller against the customers mirrored from the sheet. Only then does it decide a text-back is warranted. This is Part 2.
  • Compose text-back. One Bedrock Haiku 4.5 call takes the handful of facts it’s allowed — the caller’s first name if known, the business name, the booking link — and writes a single short, friendly SMS in your voice. The model writes words and nothing else; it never decides whether to send, to whom, or which link to use. This is Part 3.
  • Route replies. When the caller texts back, that reply lands on the same webhook, is matched to the original missed call, and is threaded to the right person or queue. The system doesn’t try to hold the conversation; it makes sure a human sees the reply with the full thread. This is Part 4.
  • Escalate. The lane for everything that shouldn’t be left to an automatic text: an unmatched caller, a reply that reads as urgent, and — via a scheduled sweep — any text-back that’s gone unanswered past a set window. Each lands with a person, with the call and the thread attached. This is Part 5.

In plain words

It’s 1:10pm and the salon’s only stylist is mid-colour when the phone rings out. The provider fires a missed-call webhook for +44 7700 900412. The system matches that number to Priya, who was in three weeks ago, and within about ten seconds her phone buzzes: “Hi Priya — sorry we missed your call at Bloom! We’re with a client right now. Text us here and we’ll sort you out, or grab a slot at bloomhair.uk/book.” She taps the link, books a cut for Friday, and never had to ring back. Nobody at the salon touched a thing until the booking dropped in.

An hour later a different number rings out twice in a minute, then texts back: “my mum’s appointment is in 20 mins and we’re stuck in traffic, are we ok?” That isn’t a booking nudge — it’s time-critical. The system has already sent its one text-back; it does not try to answer the question. It threads the reply, flags it urgent, and pushes it straight to the front desk’s phone so a person can ring them in the next minute. One text-back, then a human, with the whole thread already in hand.

Design rules that shaped every decision

  • One missed call, one text. Repeat rings from the same number collapse to a single reply — it never spams.
  • It opens the door, it doesn’t walk through it. The system texts back and threads replies; it never books, quotes, or promises.
  • A confident match or a plain greeting. Known callers get their name; unknown numbers get a warm generic text, and anything odd escalates.
  • The model only writes words. The trigger, the match, the dedup, and the routing are deterministic; Bedrock just phrases the SMS.
  • Quiet hours and STOP are sacred. No texts overnight, and anyone who texts STOP is suppressed for good.
  • It never goes quiet on a person. Urgent replies and unanswered text-backs are escalated to a human with full context.

Why this shape

Most small businesses handle missed calls one of three ways: they don’t know about them at all, they glance at the call log at the end of the day and ring a few back, or they pay for a receptionist or an answering service. The first loses the customer silently — a missed call rarely calls twice. The second is hours too late; by the evening the caller has already booked elsewhere. And a full answering service is real money every month for something a single text would have solved. The gap is the first sixty seconds, and nothing in a typical small shop is watching them.

The shape above fills exactly that gap and nothing more. It leans on the phone provider you already pay for as the trigger, keeps the customer sheet you already maintain as the source of names, and adds a small system that sends one good text the instant a call is missed. The common case — “I just wanted to book” — turns into a tap on a booking link with no human involved. The few that are genuinely urgent or off-script are pulled out early and put in front of a person, with the call and the conversation already gathered.

The next four posts walk through each piece in turn: how a missed call gets caught and matched, how a text-back gets composed, how a reply gets routed, and how an unanswered call-back gets escalated. One diagram per post. A cost breakdown and a final engineering reference at the end.

All posts