--- name: land-register description: Free e-kinnistusraamat index search: register part, cadastral unit, address, area, KÜ code, land use. module: kinnistusraamat.mjs execution: get --- # Estonian Land Register index (e-kinnistusraamat) The free layer is an **index**, not an extract: it resolves an address or cadastral unit to a register part and its basic facts. Owner, mortgages, servitudes and notations are paid and login-only — read `## Limits` before promising an encumbrance check. ## Vetted module (use this first) `kinnistusraamat.mjs` ships in https://kodanikukratt.ee/kratt-agent.tar.gz (plain ESM, Node 22+) and is re-verified against the live source: ```js import { show } from "./kratt.mjs"; import { landRegisterSearch } from "./kinnistusraamat.mjs"; const r = await landRegisterSearch("Vabriku tn 12, Tallinn"); show({ kokku: r.total, vasteid: r.matched, truncated: r.truncated, page: r.page, note: r.note }); show(r.rows); // the rows that really match the query show(r.nearby.map((n) => n.aadress)); // the street neighbours the fuzzy search also returned ``` - `landRegisterSearch(term)` takes an address, a katastritunnus (`78401:101:5214`) or a registriosa number (`2349701`). The register's address search is fuzzy at street level — "Vabriku tn 12, Tallinn" returns 15 rows led by Vabriku 31 — so the module splits them: `rows` match every word of the query, `nearby` is everything else. **A street neighbour presented as the answer looks exactly like a correct answer**, so read `matched` before quoting a number. - **`total` is the register's own count and `rows` may be fewer.** The result page renders 25 rows and reports its count separately (29 against 25 rendered, for one Vabriku 31 query); `truncated` says when that happened. State counts from `total`. - **The register throttles anonymous searches with a CAPTCHA** — measured at the fourth search in a row, clearing after about half a minute. The module waits it out and retries, and if it still cannot get through it says so. A captcha page is not "this address does not exist", and nothing may report it as one. - `note` carries the boundary this recipe exists for: no owner, no mortgage, no servitude, no notation. The answer has to say that they were not retrieved. - `source` and `page` are the same URL here — the search result opens in a browser without a login — and it is the only link a result entitles you to add. The endpoints below are the fallback if a module call throws. ## Access Application: `https://kinnistusraamat.rik.ee/` (ASP.NET) — the app shell, which opens on a blank search form. Exactly one endpoint answers anonymously, with no payment: ```text GET https://kinnistusraamat.rik.ee/PealeheOtsinguTulemus.aspx?term={query}&kehtetuOmanik=false&oigustatudIsik=false&otsi=1 ``` Send `Accept: text/html` only to override a client that asks for JSON by default, as `get()` does — a fetch sending no `Accept` at all returned the same page with `main-result-table` and `fields_HiddenResCount` present (verified 2026-08-03 on `78401:101:5214`), so an agent that cannot set headers can still run this. `term` accepts an address (`Vabriku tn 12, Tallinn`), a cadastral unit number (`78401:101:5214`) or a register part number (`2349701`). Address matching is fuzzy at street level, so a street query returns the neighbours too — pick the row whose address matches. **Search by cadastral unit whenever you can.** `address-search` turns a free-text address into one, and that number returns a single exact row where the address text returns the street. It also settles which town was meant before this register is asked — the address query cannot, and answers about the wrong Vabriku 12 look identical to right ones. Everything else on that host requires TARA login (ID-card / Mobiil-ID / Smart-ID). `GET .../KRavalikTeated.aspx` redirects to `Login.aspx?ReturnUrl=…`; `SearchResultPrint.aspx` and the `default.aspx?LoadToFile=true…` export both need the logged-in session and return an empty page or a redirect without it. ## Retrieve Parse `
| /g)].map((c) => cell(c[0])))
.filter((r) => /^\d+$/.test(r[1] ?? "")) // data rows start with the register part number
.map((r) => ({ kinnistuNr: r[1], liik: r[2], katastritunnus: r[3], aadress: r[4], pindala: r[5] }));
show({ source: url, kokku: p.match(/HiddenResCount" value="(\d+)"/)?.[1], rows }, 3000);
```
Zero results render "Otsingutulemused puuduvad.", no `main-result-table`, and `HiddenResCount` = 0.
## Return
Preserve `Kinnistu nr`, `Kinnistu liik`, `Katastritunnus`, the full `Katastriüksuse aadress`, `Pindala`, eriomand count, `Korteriühistu registrikood`, `Sihtotstarve`, the query term, the match count and the URL fetched. State explicitly that ownership and encumbrances were not retrieved.
**The `PealeheOtsinguTulemus.aspx?term=…` URL you fetched IS the citation.** It needs no login and renders the same result table in a browser (verified anonymously 2026-07-28), so it is both the source and the page the citizen can open. The application root above is a pointer, not a source: citing it in place of the URL that carries the row tells the reader the answer came from a blank form.
## Where the rest of a property check comes from
These are recipe names, not links. To point the citizen at one, query it and cite what came back; a register this run did not open may be NAMED in the answer but never linked — a domain built from a register's name is a guess that looks like a source.
- Cadastral geometry, restrictions and map layers: `geospatial-open-data`. The result page also builds a Maa-amet link: `https://xgis.maaamet.ee/xgis2/page/app/maainfo?showsearchlayer=1&hide=true&searchid=FADS0703&ORIG_TUNNUS={katastritunnus}`.
- Buildings, building permits and kasutusluba on the plot: `construction-register`.
- The korteriühistu behind a `Korteriühistu registrikood`: `business-register-open-data`.
- Detail plans and public-display windows affecting the plot: `planning-decisions`.
- If the object is on a forced-sale auction, its **III and IV jagu encumbrances are published in full for free** in the auction notice — see `bailiff-proceedings`.
- Kinnistusraamatu teated in Ametlikud Teadaanded: main type `kinnisturaamat`, subtypes `kinnistusraamatu-registriosa-avamine`, `kinnistusraamatust-eelmarke-kustutamise-noue`, `kohtu-kinnistusosakonna-maaruse-kattetoimetamine` — via `official-notices`.
- Paid-layer prices, if the citizen asks what a full check costs: `https://www.rik.ee/et/e-kinnistusraamat/e-kinnistusraamatu-portaal/teenuste-hinnad` (fetch it; do not quote from memory).
## Limits
- The free layer answers "which register part and cadastral unit is this address, how big is it, what is it for" — it contains **no owner, mortgage, servitude, notation or document data**, so it cannot complete an encumbrance or ownership check on its own.
- The paid sections (I jagu, II jagu owner, III+IV jagu encumbrances, whole register part) need a login or a card payment. Do not buy data; tell the citizen the price and the route.
- Searching by a private person's name or isikukood is refused by the register itself ("Eraisiku nime või isikukoodi järgi kinnistuid otsida ei saa"), so "what property does X own" is not answerable here.
- Viewing personal data in the paid layer is logged to the subject's eesti.ee andmejälgija for a year — worth telling a citizen who is about to look someone up.
## Verify
- A retrieval counts only when ` |