---
title: "The indexation clock: the increase your contract already allows, and nobody sent the letter"
subtitle: "Every recurring contract with its index, its anniversary and its notice period in one list, so the annual rise arrives as a signed letter on time instead of as a regret two years later"
url: "https://rxed.ai/blueprints/contract-indexation-clock.html"
id: "contract-indexation-clock"
version: "1.0"
published: "2026-08-31"
kind: "workflow"
setup_effort: "A weekend"
setup_hours: "6-12"
running_cost_usd_per_month: "0-12"
paid_software_usd_per_month: "0"
time_saved: "not a time saving - it collects the rise your contract already allows, worth ~EUR 3,000 in year one per EUR 120,000 of indexed recurring revenue at 2.5%"
time_saved_basis: "it recovers revenue rather than hours: on EUR 120,000 a year of indexed contracts, one skipped 2.5% rise is EUR 3,000 in year one and compounds into the base, against euro-area annual inflation running near 2% through 2026 (Eurostat HICP, ECOICOP v2 series prc_hicp_minr) and the Belgian health index at +2.99% year on year in June 2026 (Statbel)"
runs_by: "owner"
data_location: "your-server"
data_location_note: "Your customer list with each one's price and renewal date is your commercial position on a page. It stays on your box, and the only outbound calls are to public statistics APIs that learn nothing about you."
first_to_break: "the index feed: a statistics office renames, rebases or freezes a dataset and the old endpoint keeps answering HTTP 200 with a stale figure"
failure_signal: "silent"
problem: "Most long-running contracts already say the price may rise each year with the cost of living. Almost nobody works out the new figure in time, and in many places you can only claim a few months of it afterwards, so the rest is simply lost."
fix: "Every contract goes in one list with its start date, its price and the index it points at, and each month the official figure is fetched and the new price worked out for any contract whose anniversary is coming up. You get a draft letter with the arithmetic shown, well before the deadline, and you decide whether it goes out."
tools: ["Grist", "n8n", "Docling", "Ollama", "Docker"]
tech: ["Grist", "n8n", "Docling", "Ollama"]
repos:
  - name: "Grist"
    url: "https://github.com/gristlabs/grist-core"
  - name: "n8n"
    url: "https://github.com/n8n-io/n8n"
  - name: "Docling"
    url: "https://github.com/docling-project/docling"
  - name: "Ollama"
    url: "https://github.com/ollama/ollama"
  - name: "Baserow"
    url: "https://github.com/baserow/baserow"
categories: ["Invoicing", "Reminders", "Reporting", "Self-hosted", "n8n"]
source: "RXed AI News — https://rxed.ai"
---
# The indexation clock: the increase your contract already allows, and nobody sent the letter

> Every recurring contract with its index, its anniversary and its notice period in one list, so the annual rise arrives as a signed letter on time instead of as a regret two years later

## Before you start

- Contracts that actually contain an indexation clause - if yours do not, this is a contract-drafting job first and an automation second
- The base index value and its base year from each contract, because the ratio is meaningless unless numerator and denominator sit on the same base
- Which index each clause names, exactly: Belgian rent uses the ordinary health index, wage indexation uses the smoothed four-month average, and they are different numbers with nearly the same name
- The notice period the contract or your local rules require, and how far back indexation may be claimed - in Belgium that is three months from the written request
- Three contracts you indexed by hand last year, to backtest the engine against the figure you actually charged
- Someone with the authority to sign the letter, because this sets a paying customer's price for a year

## What breaks first

the index feed: a statistics office renames, rebases or freezes a dataset and the old endpoint keeps answering HTTP 200 with a stale figure. Exactly what happened in 2026 - prc_hicp_manr was discontinued and frozen at December 2025 while still responding. Log the dataset code and the publication date of every figure you fetch, and alert when the newest figure stops moving for two months.

One row per recurring contract, the official index each one points at, and a draft letter on your desk before the notice deadline. The rise your own contract already allows, worked out and evidenced, instead of noticed two years late.

 

### The problem

 A maintenance contract at €4,000 a month with a plain cost-of-living clause, skipped for one year at 2.5%, is €1,200 you will not invoice. That is the small part. The expensive part is that next year's rise is calculated on the base you failed to raise, so the gap never closes. Skip it three years running on a €120,000 book of recurring work and you are carrying roughly €9,000 of permanently lost margin, on a clause both parties already signed.

 Nobody skips this out of generosity. They skip it because the arithmetic is annoying in a specific way. The formula is a ratio of two index figures from two named months, and both figures have to be on the same base year. The figure you need is published about four weeks after the month it describes, so the calculation genuinely cannot be done on the anniversary itself. And the deadline is real: for Belgian leases the indexation is retroactive for a maximum of three months from your written request, so a letter sent in November for a June anniversary collects three months and loses the other two. Late is not "catch up later". Late is gone.

 Then 2026 quietly broke every script anyone had already written. In January the harmonised index moved to a new classification and a new base year, and the Eurostat dataset most tutorials point at was discontinued rather than updated. It still answers. It just answers with last year's number, forever.

 

### The architecture

 
 [ Signed contracts, PDF ]  +  [ Official index, published monthly ] 
         ▼ 
 [ Docling + local model — read the clause ONCE ] 
         │  which index, which base month, cap/floor, notice days 
         │  you confirm every field before it counts 
         ▼ 
 [ Grist — the contract register ] 
         │  customer, start date, base price, base index + its base year 
         │  the clause's own formula, as a formula 
         ▼ 
 [ n8n — monthly, on the 27th ] 
         ├─ fetch this month's index (Eurostat / Statbel / ONS / BLS) 
         ├─ which anniversaries fall inside their notice window? 
         ├─ apply the clause, including cap, floor and rounding 
         └─ draft letter + the two index figures used 
 
 Nothing leaves the building. You sign it, or you don't. 
 

 The design decision worth defending is the split between the register and the engine. The clause is data, read once and confirmed by a human. The index is a feed that changes monthly and will change shape again. Keeping those apart means the day Eurostat renames a dataset you edit one node, not fifty rows.

 

### Tool choices — and why

 Grist (Apache-2.0, 11.6k stars, v1.7.17 released 29/07/2026) is the register. Indexation is a formula, and Grist is the rare self-hosted tool that is a real database and still lets you write the formula in the cell where the accountant expects it. Columns for base index and base year sit next to the computed new price, and the working stays visible, which matters when a customer asks how you got there. Baserow (open-core, non-premium features under MIT, 5.7k stars, v2.3.3) or NocoDB do the same job if you already run one; they push more of the arithmetic into n8n.

 n8n (Sustainable Use License, free for internal business use, 202.8k stars, active) is the monthly engine. One scheduled workflow: fetch, filter, compute, draft. It is the same box the other blueprints in this library run on.

 The index feeds are free and official, and each has a catch. Eurostat's REST API needs no key, and the dataset you want is prc_hicp_minr , not the widely-cited prc_hicp_manr , which Eurostat's own page now marks discontinued. Belgium's health index comes from Statbel and is published around the 26th of the following month. The UK's ONS developer API is open with no registration, and is explicitly still in beta with breaking changes possible, so pin your parsing and check it yearly. The US BLS API is public domain: version 1 needs no key and gives you 25 queries a day, version 2 needs a free registration key and gives 500. At one call a month, version 1 is enough.

 Docling (MIT, 65.7k stars, an LF AI & Data Foundation project) plus a small model on Ollama (MIT, 179.4k stars, v0.33.2 released 27/08/2026) do exactly one job: turn a signed PDF into the six fields the register needs. Indexation clauses are prose, and prose written by six different lawyers is the case where a parser loses and a model wins. It is also the case where a model must not be trusted, so every extracted field lands in a confirm-this screen before it can drive a price. Reading is assistive; the register is human-signed.

 Running cost. Software €0. If you already run n8n for another blueprint, marginal cost is €0. Standalone, one small VPS at roughly €5–12 a month carries the register, the engine and the model for a business with a few dozen contracts. No per-contract fee, no per-seat fee, and the index data is public.

 

### Setup outline

 1. Pull your recurring contracts into one folder. Not the quotes, not the one-off jobs. The ones that renew. 
 2. Build the register in Grist, one row per contract: customer, start date, anniversary month, current price, base price, base index value, base year of that index , index name, cap, floor, rounding rule, notice days, and the date you last indexed it. 
 3. Read the clauses. Docling converts the PDF, the local model proposes the fields, and you approve each one. Budget an hour for twenty contracts and expect to correct roughly one field in five. 
 4. Wire one n8n workflow per index source. Fetch, cache the monthly figure into the register, and log the dataset code you called so a silent swap is visible in the log. 
 5. Write the clause as a formula in Grist: new price = base price × (index of the month before the anniversary) ÷ (base index), then apply cap, floor and the rounding the contract actually specifies. Both index figures must be on the same base year. 
 6. Schedule the engine monthly, after the publication date of your slowest index. Filter for anniversaries falling inside the notice window plus a safety margin — 60 days out is a sane default. 
 7. Generate the letter with the two index figures and their months printed in it. A customer who can check your arithmetic argues about it far less. 
 8. Backtest before you trust it. Take three contracts you indexed by hand last year and confirm the engine reproduces the number you actually charged. If it does not, the clause is not what you think it is.

 

### Pitfalls — the real ones

 The dataset that answers with last year's number. Eurostat discontinued prc_hicp_manr ; it is frozen at December 2025 and its replacement is prc_hicp_minr . Anything written against the old code still returns HTTP 200 and a plausible figure. This is the failure that costs you the most, because nothing looks broken. 
 Two figures, two base years, one wrong answer. From January 2026 the harmonised index runs on ECOICOP version 2 with base 2025 = 100, under Implementing Regulation (EU) 2025/1182. Belgium's health index has cohorts of its own — 1988, 1996, 2004, 2013, and 2025 for new leases from 1 January 2026. The ratio only means anything when numerator and denominator sit on the same base. Store the base year as a column, not as an assumption. 
 The right index has a near-identical wrong twin. Belgian rent indexation uses the ordinary health index. Wage indexation uses the smoothed health index, the four-month average. Same name in conversation, different number in the letter. 
 The calendar does not cooperate. The figure for the month before the anniversary is published weeks after that month ends. Run the check ahead of the date, not on it, and never build a workflow that assumes today's index exists. 
 Not every clause is a ratio. "The greater of 3% or CPI", caps, floors, threshold triggers that only fire above 5%, and ratchet wording that forbids a decrease are all common. An engine that knows one formula will apply it confidently to a contract that says something else. 
 Never auto-send. This letter goes to a paying customer and sets the price for a year. Draft, review, sign. The automation's job is to make sure the decision reaches you in time, not to make it. 
 This is not legal advice. Whether your clause is enforceable, what notice your local rules require, and how far back you may claim are questions for your own lawyer or accountant. The engine does arithmetic and keeps a calendar. It does not know your jurisdiction.

 

### Verified repos

 
 [Grist](https://github.com/gristlabs/grist-core) — Apache-2.0, 11.6k stars, v1.7.17 released 29/07/2026 
 [n8n](https://github.com/n8n-io/n8n) — Sustainable Use License (free self-hosted internal use), 202.8k stars, active (checked 31/08/2026) 
 [Docling](https://github.com/docling-project/docling) — MIT, 65.7k stars, LF AI & Data Foundation project, active (checked 31/08/2026) 
 [Ollama](https://github.com/ollama/ollama) — MIT, 179.4k stars, v0.33.2 released 27/08/2026 
 [Baserow](https://github.com/baserow/baserow) — open-core, non-premium features under MIT, 5.7k stars, v2.3.3 (checked 31/08/2026) — alternative register if you already run one
 

 Index sources, all free and official: [Eurostat prc_hicp_minr](https://ec.europa.eu/eurostat/databrowser/product/view/prc_hicp_minr) (no key) · [Statbel consumer price and health index](https://statbel.fgov.be/en/themes/consumer-prices/consumer-price-index) · [ONS developer API](https://developer.ons.gov.uk) (open, beta) · [BLS Public Data API](https://www.bls.gov/developers/api_faqs.htm) (public domain; v1 keyless, 25 queries/day).

 
 Get the next blueprint as it publishes — free, practical, verified tooling only.

 [Subscribe](https://subscribe.rxed.ai) · Want it audited or extended for your business? DM [@RXed_EU](https://x.com/RXed_EU)
