Part 1 of 7 · Back-in-stock notifier series ~10 min read

A back-in-stock notifier on AWS for a few dollars a month

A sold-out product is a small, silent leak: the customer who wanted it taps away, the stock trickles back a fortnight later, and whoever happens to be looking that morning gets it while everyone who actually asked to be told hears nothing. This post walks through the design of a small serverless system that turns “notify me” into a fair, orderly queue — first come, first told, with a short window to buy — and never promises more than it can deliver.

Key takeaways

  • A shopper taps “notify me” on a sold-out item; the request is stored against that exact SKU and joins a per-item queue.
  • When the store’s inventory reports that SKU back above a threshold, the waiting list is texted or emailed in the order they joined.
  • Each notice carries a short-lived reserve link, so the first people to respond actually lock the stock before it sells out again.
  • It notifies once per restock, honours opt-out, and caps the batch to the units available so it never oversells.
  • Designed on AWS for about $2.10/month at roughly 120 requests a month. One Bedrock call phrases each notice; everything else is plain Python.

The whole system on one page

Before any code, here’s the shape of what we’re designing. Every shop that sells popular things sells out of them, and a sold-out product page is a quiet leak: the customer who wanted it taps away, the stock trickles back a fortnight later, and whoever happens to be looking that morning gets it while everyone who actually asked to be told hears nothing. The system below catches that moment on both ends: it remembers who asked, for what, and in what order — and when the item comes back, it tells them, oldest first, with a short window to buy.

System architecture: a shopper and the store’s inventory outside, four pieces inside AWS that capture, detect, notify, and reserve At the top, three external boxes in a row. Far left, “Shopper” — the customer’s phone and browser, which taps “notify me” on a sold-out product, receives the text or email when it returns, and clicks the reserve link. Centre, “Store inventory & storefront” — the shop platform that fires a stock-level webhook when an item comes back and holds the catalogue and checkout the reserve link 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 shopper sends the notify-me request in and later receives the notice out; the store sends restock events in and receives reserve holds; your team receives exceptions. Inside the AWS account are four components. Left, Capture request — receives the notify-me tap, validates it, keeps one active request per person per item, checks opt-out, and appends the request to a per-SKU waiting list stamped with the moment it joined. Next, Detect restock — receives the inventory webhook, verifies it, spots the genuine crossing from below to above the threshold, works out how many units came in, and fires one notify batch per restock. Next, Notify the list — reads the queue oldest-first, caps the batch to the units available, phrases one notice with a Bedrock call, and sends each person a personalised reserve link in join order. Below the middle sits Hold & expire reservation — a reserve-link click holds a single unit without overselling, and a scheduled sweep expires unclaimed holds and stale requests, offering any freed unit to the next person in line. Arrows flow from capture into the waiting list that notify reads, from detect into notify, and from notify down into hold, with the sweep looping back. A note at the bottom reads: it notifies in the order people joined, once per restock, and caps each batch to the units available so it never oversells. Shopper taps notify-me, gets notice Store inventory stock webhook, checkout Your team where exceptions land notify-me in, notice out restock in, reserve hold exception with context AWS account Capture request validate, dedup, opt-out, join the per-SKU queue Detect restock verify webhook, spot the crossing, count the units Notify the list oldest first, capped to qty, reserve link each the waiting list it reads batch Hold & expire reserve a unit, sweep the unclaimed back to the queue reserve link freed unit → next in line It notifies in the order people joined, once per restock, and caps each batch to the units available — so it never oversells.
Fig 1. Two things outside, four pieces inside AWS. A shopper joins the queue through Capture; when Store inventory fires a restock, Detect counts the units and Notify messages that many people oldest-first with a reserve link each; Hold locks the stock and sweeps any unclaimed unit back to the next person in line.

What you set up once (the outside)

  • The store inventory and storefront. Whatever platform already runs the shop — it needs to do two things: fire a webhook when a SKU’s stock level changes (most e-commerce platforms emit an inventory or product-update event), and hold the checkout the reserve link points to. You point the platform’s webhook at one AWS URL and store its signing key in Secrets Manager. This is the trigger for every notice; the catalogue supplies the product names, and the checkout is where a reserved unit is actually bought. It’s covered in Part 3.
  • A “notify me” control and a small settings doc. A button on your sold-out product pages that posts the shopper’s contact and the SKU to a second AWS URL — nothing more than a name, a phone or email, and the product id. Alongside it sits a small settings doc: the store voice for the notices, the restock threshold per item (how many units in stock counts as “back”), how long a reserve link stays live, and the escalation rules. You already know these numbers; this just puts them where the system can read them.
  • Your team. The person who picks up anything the system deliberately won’t decide on its own — a restock that looks wrong (a thousand units appearing at 3am), a SKU with no matching catalogue entry, a bounce that won’t deliver. They get a message with the item, the queue length, and what happened. The system opens the door for the customer; a human handles the odd cases behind it.

What runs on every restock (the inside)

  • Capture request. The notify-me button posts to one Lambda Function URL. The function validates the request, keeps exactly one active request per person per item (a second tap doesn’t create a second place in the queue), checks the opt-out list, and appends the request to the per-SKU waiting list stamped with the moment it joined. This is Part 2.
  • Detect restock. The store posts a stock-level webhook to a second Function URL. The function verifies the signature, decides whether this is a genuine crossing from below the threshold to above it (rather than a level wobbling around the line), works out how many units came in, and fires exactly one notify batch for that restock. This is Part 3.
  • Notify the list. A worker reads the per-SKU queue oldest-first, caps the batch to the units available so it can never invite more people than there is stock, phrases one notice in your voice with a single Bedrock call, and sends each person their own short-lived reserve link — in the order they joined. This is Part 4.
  • Hold and expire reservation. A reserve-link click holds a single unit with a write that can never take the count below zero, then hands the shopper to checkout. A scheduled sweep expires holds that aren’t used inside the window and requests that have gone stale, returning any freed unit to the next person waiting. This is Part 5.

In plain words

Loom & Last is a small independent homeware-and-footwear shop in Frome. Their walnut dining chair sells out constantly. One Tuesday, Della lands on the sold-out chair page and taps “notify me”; the system records her request against that SKU and puts her at position seven in the queue. Over the next two weeks another dozen people do the same. A fortnight later a delivery lands and the shop’s inventory posts the chair back in at four units. The system sees the crossing, works out there are four to sell, and texts the first four people in the queue — Della is one of them: “Good news — the walnut dining chair is back at Loom & Last. You’re near the front of the list. Here’s a link that holds one for you for the next 15 minutes: loomandlast.co.uk/r/….” Della taps it, the chair is held, she checks out. Nobody at the shop touched a thing.

The fifth person in the queue, Marcus, hears nothing yet — there were only four chairs, and the system will not invite a fifth person for four units. But one of the four never taps their link. Fifteen minutes later the expiry sweep notices that hold went unused, returns that chair to the pool, and texts Marcus: he’s next in line, and now there’s one for him. The queue moved by exactly one, in order, and at no point were there five live reserve links for four chairs. One restock, four units, told fairest-first, and never oversold.

Design rules that shaped every decision

  • First come, first told. People are notified in the exact order they joined the queue — oldest request first, no jumping.
  • Never more invites than units. Each restock’s batch is capped to the quantity that came in, so the system can’t oversell.
  • A notice, then a hold. The reserve link locks a single unit for a short window; the first to respond genuinely get the stock.
  • Once per restock. Each person is told at most once per restock event; a flapping stock level doesn’t spam anyone.
  • The model only writes words. The queue order, the cap, the dedup, and the holds are deterministic; Bedrock just phrases the notice.
  • The line keeps moving. Unclaimed holds and stale requests expire and pass to the next person, and opt-out is honoured for good.

Why this shape

Most shops handle back-in-stock one of three ways: they don’t — the item quietly returns and sells to whoever’s looking; they blast everyone who ever asked the instant a single unit lands, so forty people race for four and thirty-six are annoyed; or they bolt on an app that emails the whole list at once with no reservation, which is the same scramble with a nicer template. The first wastes the demand you already captured. The second and third turn a happy moment into a disappointment for most of the list, and risk overselling when several people buy the same last unit in the same minute.

The shape above fixes exactly that. It leans on the inventory feed the store already emits as the trigger, keeps the notify-me request small and de-duplicated so the queue is honest, and adds a notifier that respects the order people joined and never invites more people than there are units. The reserve link is the quiet hero: it converts “it’s back, go!” into “it’s held for you for fifteen minutes”, which is what makes first-come-first-told actually mean something. The odd cases — a restock that looks wrong, an item with no catalogue entry, a message that won’t deliver — are pulled out and put in front of a person.

The next four posts walk through each piece in turn: how a request gets captured, how a restock gets detected, how the waiting list gets notified, and how a reservation gets held and expired. One diagram per post. A cost breakdown and a final engineering reference at the end.

All posts