A tax rate updater on AWS for a few dollars a month
Every business has tax numbers written down in places nobody remembers. A VAT rate in a quoting spreadsheet. A mileage rate in a claim form. A registration threshold in somebody’s head. A duty rate typed into a shipping template in 2021. None of them are in a system that gets updated, and all of them are wrong the moment the government changes something. The first anyone finds out is an invoice a customer queries, or worse, one they do not. This post walks through a small system that keeps the list and watches the sources.

Key takeaways
- The register is the product. Listing where every rate lives is most of the value.
- It watches official publications, not aggregator sites, and records what it read.
- A change produces a dated notice with a checklist, not an edit.
- It watches for the change being announced, not for it taking effect. Those are months apart.
- Designed on AWS for about $2 a month.
The whole system on one page
Before any code, here is the shape of what we are designing.
- Management
- Analytics
- People
- Outside AWS
The register is the product
The code in this system is trivial. The register is not, and building it is a genuinely useful exercise that most businesses have never done. Each row is one rate, the source that publishes it, and every place in your business that holds a copy of it.
| Column | Example | Why |
|---|---|---|
| Rate | Standard VAT rate | What it is, in plain words |
| Current value | 20% | What you believe it to be today |
| Source | The official VAT rates page | Where the truth lives |
| Effective from | 2011-01-04 | When the current value started |
| Used in | Quoting sheet, price list PDF, invoice template, Shopify tax setting | The checklist. This column is the whole point. |
| Owner | finance@ | Who gets the notice |
The Used in column is what makes this different from any tax API. An API can tell you the VAT rate. It cannot tell you that your printed rate card, your quoting spreadsheet and a hard-coded constant in your booking form all contain a copy of it and all need changing. Nobody knows that except you, and most businesses have never written it down.
What runs on every check (the inside)
- The watcher. Fetches each source on a schedule, extracts the values it cares about, and stores exactly what it read along with a copy of the page. That last part matters more than it looks: when somebody asks in eighteen months why a rate was applied, the answer is a stored snapshot rather than a memory.
- The differ. Compares what was read against what the register says. The interesting output is not “it changed” — it is the effective date, because rates are almost always announced months before they apply, and the whole value of the system is in that gap.
- The notifier. Sends one notice per change to the owner, with the old value, the new value, the effective date, the source link, and the checklist of places from the register. Then it reminds them again shortly before the effective date, because a change announced in March for October will absolutely be forgotten by September.
One change, end to end
- App integration
- Management
- Analytics
- Outside AWS
In plain words
In March, the government publishes that a threshold you rely on will rise in the following April. The watcher’s daily check picks it up within a day. The differ reads the effective date, notices it is thirteen months away, and files it. The notifier sends one message in March: what changed, from what to what, effective when, with the link, and the checklist — the quoting spreadsheet, the two paragraphs on the website, the accountant’s standing instruction, and the config value in the booking form.
Nobody does anything in March, which is fine and expected. In the following March, four weeks before it takes effect, the same message arrives again, marked as a reminder. Now somebody acts, because it is imminent and because the checklist means acting takes twenty minutes rather than being an open-ended research task. The alternative — and this is what actually happens without a system — is that three of the four places get updated by whoever remembered, and the fourth is discovered eight months later by a customer.
Design rules that shaped every decision
- It never edits anything. A live price list carries pricing and contract consequences, and changing one is a business decision.
- Watch official sources only. Aggregators and news sites are faster and occasionally wrong, and being wrong about a tax rate is much worse than being late.
- Store what was read, not just what was extracted. A snapshot of the page is the audit trail.
- The effective date is the important field, not the value. Announcement and effect are usually months apart.
- Remind before the effective date. An announcement noticed and forgotten is the same as an announcement missed.
- A source that stops being readable is an alarm, not silence. The failure mode of a watcher is quietly watching nothing.
Why this shape
Tax software solves the transaction problem: what rate applies to this sale, right now. It solves it well and this system does not try to compete with it. The problem here is different and almost entirely unaddressed — the rates that live outside any system, in documents and spreadsheets and templates, where nothing updates them and nothing knows they exist.
That problem is not solvable by software alone, because the crucial information lives only in people’s heads: where the numbers are. So the design puts almost all of its weight on the register, makes maintaining it cheap, and adds the only automatable part — watching the sources and remembering the dates — around it.
The next four posts walk through each piece: how the register works, how a source gets read, how a change gets dated, and how the reminder works. One diagram per post, a cost breakdown, and an engineering reference at the end.
All posts