Documentation

The complete tool surface, generated from the running server. Every tool it has registered is on this page; the prose around them is written by hand, the names, inputs and values are not.

POST https://mcp.solgt.no/mcp Authorization: Bearer sk_…

One Streamable-HTTP endpoint, one sk_ bearer token. The config snippets for Claude Desktop, Claude Code, Cursor, VS Code and the rest live on the front page.

Setup instructions →

This reference is in English because it is generated from the live tool definitions, and those are English — a hand-translated copy would go stale the first time a parameter changed, with nothing able to catch it. Forsiden er på norsk.

You have a key. Now what?

Three calls, about five minutes, no SDK. If you are connecting an AI client rather than calling the endpoint yourself, the ready-made config for Claude Desktop, Claude Code, Cursor, VS Code and Copilot is on the front page — this is the same thing at the wire level, and it is how you check a key before you paste it anywhere. ChatGPT and Claude.ai users need no key at all: add https://mcp.solgt.no/mcp as a connector and sign in with the email your administrator registered (OAuth 2.1 — the server publishes its metadata at /.well-known/oauth-protected-resource/mcp).

Ready-made config for Claude Desktop, Claude Code, Cursor, VS Code and Copilot →

  1. 1 · Does the key work?

    tools/list needs no initialize first — the server is stateless, so one POST is a complete conversation. Three headers matter: the content type, an Accept that allows text/event-stream, and the bearer token.

    curl -s -X POST https://mcp.solgt.no/mcp \
      -H "Content-Type: application/json" \
      -H "Accept: application/json, text/event-stream" \
      -H "Authorization: Bearer <YOUR_API_KEY>" \
      -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
    event: message
    data: {"result":{"tools":[{"name":"summarize_sold_homes","title":"Summarize Sold Homes (aggregate statistics)","description":"AGGREGATE STATISTICS ONLY over Norwegian SOLD homes …
    
    … and one entry per tool your key can call …

    The answer comes back as one Server-Sent-Events frame — an event: line, then the JSON on a data: line — because the transport is Streamable HTTP. Strip the data: prefix and you have ordinary JSON-RPC. A key that is not recognised answers as plain JSON instead, with no SSE frame at all: {"jsonrpc":"2.0","id":null,"error":{"code":-32001,"message":"Unauthorized: key_unknown"}}.

  2. 2 · Ask about a real property

    tools/call with a name and an argument object. resolve_property is the first hop for any question about one property, and an address is what a human actually has.

    curl -s -X POST https://mcp.solgt.no/mcp \
      -H "Content-Type: application/json" \
      -H "Accept: application/json, text/event-stream" \
      -H "Authorization: Bearer <YOUR_API_KEY>" \
      -d '{
        "jsonrpc": "2.0",
        "id": 2,
        "method": "tools/call",
        "params": {
          "name": "resolve_property",
          "arguments": { "address": "Akersgata 32", "kommune": "Oslo" }
        }
      }'
    event: message
    data: {"result":{"content":[{"type":"text","text":"Resolved 21 of 21 requested properties via address …
    \"Akersgata 32\" in kommune 0301 → 21 of 21 unit(s) at entrance Akersgata 32. These units ARE the answer (level: mixed).
    
    {
      \"status\": \"ok\",
      \"shown\": 21,
      \"total\": 21,
      \"next\": {
        \"get_conveyances\": { \"unitkeys\": [\"0301-208-1-0-0\", \"0301-208-1-0-1\", … ] },
        \"get_owners\":      { \"unitkeys\": [\"0301-208-1-0-0\", \"0301-208-1-0-1\", … ] }
      }
      …
    }"}]}}

    Every tool answers as one text block: a few lines of plain prose about what happened, then the JSON payload. The prose is meant to be read — it carries the caveats that belong with the numbers.

  3. 3 · Carry next into the following call

    next is not a hint. Each entry there is a finished argument object for the tool it is named after — paste it in as-is and the second question is answered. The answer below is the text block from inside the data: frame, unwrapped; that is what your client shows the model.

    curl -s -X POST https://mcp.solgt.no/mcp \
      -H "Content-Type: application/json" \
      -H "Accept: application/json, text/event-stream" \
      -H "Authorization: Bearer <YOUR_API_KEY>" \
      -d '{
        "jsonrpc": "2.0",
        "id": 3,
        "method": "tools/call",
        "params": {
          "name": "get_owners",
          "arguments": { "unitkeys": ["0301-208-1-0-4"] }
        }
      }'
    1 registered owner(s) across 1 of 1 requested property.
    A private individual's number is masked (DDMMYYXXXXX); a company's organisasjonsnummer is public and shown in full.
    
    {
      "status": "ok",
      "shown": 1,
      "total": 1,
      "properties": [
        {
          "requested": "0301-208-1-0-4",
          "level": "unit",
          "type": "Seksjon",
          "owners_status": "ok",
          "owners": [
            {
              "navn": "AKERGREN AS",
              "safe_number": "982022568",
              "type": "JuridiskPerson",
              "ownership": { "prosent": 100, "type": "Eiendomsrett" }
            }
          ]
        }
      ]
    }

    That is the whole loop: resolve once, then pass next on. Everything else on this page is which tool to reach for, and what its answer means.

All tools at a glance

Every tool the server has registered, with what it is for. The table is built from the registry, so it cannot fall behind the surface it describes.

Tool Answers What it is for
summarize_sold_homes Market statistics Aggregate statistics over verified sold homes: counts, averages, kr/m², sold-vs-asking and days on market — by municipality, county or bydel, over a window of up to 12 months.
summarize_homes_for_sale Market statistics The same engine pointed at the active for-sale inventory: how much is on the market, at what asking price per m², how long it has been listed.
search_sold_homes Market statistics The individual sold records behind the statistics — one row per home, each with its new_unitkey, a Finn URL, a Solgt URL, sold and asking price, area and dates.
search_homes_for_sale Market statistics The individual active listings: asking price, total price including omkostninger, days on market, area and agency, each with a Finn and a Solgt URL.
get_homes_by_unitkey Market statistics Drill-down by new_unitkey: for up to 25 keys, the latest sold record and the active for-sale record for each, merged into one entry per key.
describe_dataset Vocabulary The data dictionary for the market datasets: the aggregate-vs-raw split, the exact values you can filter on, what each metric means, and worked examples in Norwegian.
list_agencies Vocabulary The canonical agency and brand names you can filter or rank by, with each brand's ad_count and office_count.
resolve_property Find the property The first hop for anything about one specific property. Give it an address, a matrikkelnummer, a new_unitkey, a finnkode or a registerenhet id; get back the property, the level it sits at, and the keys every other property tool needs.
get_encumbrances What is registered on it What is registered against a property in grunnboken — pant, servitutter, anmerkninger and the rest of the 16 heftelse types, grouped, with each row's rettsstiftelsestype, amounts, free text and rettighetshavere.
get_avm What it is worth The Solgt.no valuation of one home: a point estimate in kroner with a low–high confidence band and kr/m², time-adjusted to today, next to the registered facts the model was given — size, build year, floor, standard scores.
get_comparable_sales What it is worth The verified sales the valuation model itself scores as most comparable to one home — each with address, sold date and price from the tinglyste omsetning, kr/m², the sale re-priced to today, what that sale implies the subject is worth, and a 0–100 similarity score.
get_price_index What it is worth The Solgt.no price index for one home over a chosen window — quarterly, rebased to 100 at the window start so 118.4 reads directly as +18,4 % — with the property's own registered sales overlaid and adjusted to today's price level.
get_conveyances What it has been through Every tinglyst overdragelse on a property, newest first: date, omsetningstype, vederlag, dokumentavgift, fellesgjeld where recorded, and the buyers and sellers.
search_conveyances What it has been through The screen the single-property history cannot do: every tinglyst overdragelse in a kommune of a given kind in a date window — arv, tvangssalg, gave, fritt salg — one row per transfer, newest first, with the property, its address, the price where one was recorded and the parties as the grunnbok names them.
get_innsyn_cases Municipal cases The municipality's own journal for a property: byggesaker, delesaker, seksjonering, tilsyn, konsesjonsfrihet, ferdigattest, plansaker — newest first, each with the documents attached to it.
get_owners Who owns it Who is registered as owner today, for up to 25 properties at a time — straight off the matrikkel/grunnbok spine.
get_property_facts Find the property What is actually there, as the matrikkel records it: the buildings standing on the property with their type, floor area and floors, everything that has been built onto them, any rental listing or parking registered on it, and the date it last changed hands.
resolve_owner Who owns it A name in, the parties that actually exist out. It resolves companies and private individuals alike, because grunnbok ownership is public record.
resolve_company_group Who owns it A group name in, every company in the konsern out — and what they all own, counted as one portfolio. A Norwegian property group is a holding company plus a fan of single-purpose companies whose names carry no trace of it; the portfolio is the union of all of them.
get_company Who owns it Everything the registers hold about one company, by organisasjonsnummer: master data, the latest annual filing, the dated shareholder register (2020–2025), current board and auditor roles, its subsidiaries, and how much property it holds.
get_owner_portfolio Who owns it Everything a party is registered on right now, paged, with the whole portfolio counted even when only a page is shown.
get_owner_history What it has been through What a party used to hold, and whether they actually let go of it.
search_properties Find the property Find properties in a municipality, several municipalities, a county or the whole country without knowing which ones: filter by type, seksjonering, bydel or a named område inside the kommune (delområde/grunnkrets — every kommune has them, bydel only six cities do), gårdsnummer, what the buildings are used for, what kind of buildings they are, whether the owner is a company or a private individual, and how many dwellings, owners and square metres of floor area the property has.
search_commercial_properties Businesses and premises Every property a kind of business operates from, with who runs the shop, who owns the building and who owns them. search_properties finds properties by what the register records about the property itself; this one finds them by the business standing on it.
search_companies Businesses and premises The one set tool that returns COMPANIES rather than properties: which legal entities are registered in a catchment, how many people they employ, what they do, how old they are and whether they can be reached. It never touches the matrikkel and never says who owns a building.
search_property_holdings Businesses and premises Næringseiendommer by their ownership and tenancy profile: one row per matrikkelenhet with the registered owner, a derived profile of that owner (eiendomsselskap, SPV, konsern, portfolio size, legal form), how many businesses stand registered on the property, related-party presence and a local rent estimate.
get_company_financials Who owns it The filed annual accounts for up to 25 companies in one call: revenue, operating result, net result, equity, total debt, total assets and the equity ratio. Built for portfolios, where the question is how solid a fan of single-purpose companies is rather than how one of them did.
search_parking_facilities Businesses and premises The 22 296 parking areas Statens vegvesen holds a registration for, each with its capacity, its charging and accessible spaces, and the operator behind it — resolved through the register of 585 parking providers and on into the company register for that operator's næringskode and size.
get_commercial_rent_stats Market statistics Median, p25 and p75 asking rent for næringslokaler in kr/m²/år, over a geography you name — the first tool on this surface that answers with a derived number rather than with rows. It returns no properties and no listings.
get_commercial_sale_stats Market statistics Median, p25 and p75 PRISANTYDNING for commercial premises, holiday property and bare land — in kroner, or per square metre with the area basis named. The sale-side twin of get_commercial_rent_stats, over the same engine.
get_residential_rent_stats Market statistics Median, quartiles and kr/m² per month of ASKING RENT for homes, from rental adverts, over a kommune, a bydel, a fylke or a set of postal codes — with the number of ads behind every figure.
get_property_tenancy Businesses and premises One property in, the businesses registered on it out — each with its næringskode and its parent company — together with the party holding the deed and whether the two are the same interest. The single-property inverse of search_commercial_properties.
get_property_occupants Businesses and premises The businesses registered at one property, in one cheap indexed hop: name, orgnr, branch-or-company, parent orgnr, and whether the registration belongs to the property's own registered owner or to someone else.
get_registered_leases Businesses and premises The tinglyste leieforhold on a property — leases someone paid to register in the grunnbok — with tenants, the nominal yearly rent of the tinglysing year, area and kr/m² where recorded, and the registered text lines.
get_listing_full Market statistics One Finn ad, whole: the seller's presentation as it ran — title, prices with omkostninger, key facts, every image with its megler caption, viewings, price history, and the ad's own matrikkel keys for checking the claims against the registers.
get_salgsoppgave Market statistics The listing's own documents read as text — the salgsoppgave with the takstmann's tilstandsrapport and the verditakst inside it, which is where the TG-graderinger live — plus TG2/TG3/TGIU counts and the takstmann's kostnadsanslag in kroner, both parsed from that text.
get_nearby_places Find the property What lies around a property, and how far it really is: the three nearest of each kind of place — bus, train, tram, metro, ferry, airport, university, school, kindergarten, supermarket, mall, department store, convenience store, ski resort, shore, lake, city — with the walking and driving distance routed along the actual network, not drawn as a straight line.
generate_transactions_data Retired names Retired name for summarize_sold_homes. Identical behaviour and arguments.
generate_listings_data Retired names Retired name for summarize_homes_for_sale. Identical behaviour and arguments.

Keys and levels

Everything hangs off one key, new_unitkey, and off which level it points at. Never build one by hand — the shapes below are how to read the ones you are handed.

0301-211-69-0-12

Five segments, always: kommunenummer, gårdsnummer, bruksnummer, festenummer, seksjonsnummer. All five are present in every key we return and every key we accept. A three-part key is not a short form — it is not a key, and the surface refuses it rather than guessing what you meant. Loose matrikkel parts have their own door: { matrikkel: { knr, gnr, bnr } }, and anything a human typed goes to { address }.

0301-208-1-0-0

A matrikkelenhet — level parcel. Festenummer and seksjonsnummer are both 0. This is the ground and, usually, the building on it.

0301-208-1-0-4

A seksjon — level unit. Seksjonsnummer above 0. It has its own owner, its own heftelser and its own transfer history, none of which it inherits from the matrikkelenhet it sits in.

knr-gnr-bnr-fnr-snr, fnr > 0

Any key whose fourth segment is not 0 is a festegrunn — level parcel. It is a matrikkelenhet of its own on someone else's ground, so it does NOT inherit the landowner's cases, heftelser or owners. Reading it as the landowner's property is a wrong answer that looks clean.

989760890-13

A borettslagsandel — level unit. The borettslag's organisasjonsnummer and the andelsnummer. Two segments is a complete, valid key here, not a truncated five-segment one. An andel names no matrikkelenhet at all, which is why municipal cases cannot be asked from it directly.

The level decides the answer, not just the rows — and it decides it differently for different questions. Municipalities file 99.5 % of their cases against the matrikkelenhet, so saksinnsyn must be asked with the parcel key alongside the unit key; that is precisely what next.get_innsyn_cases carries, and the reason to pass it through rather than assemble it. Heftelser run the other way: a parcel and its seksjoner each have their own, and an empty answer at parcel level says nothing about the apartments. And a house letter is an entrance rather than a seksjonsnummer: 54B is not seksjon 2, and a key built that way names a different property.

How the surface says no

Read the status before the numbers. These are different statements about different things, and collapsing them into "there are none" is the one failure mode that produces a confident wrong answer.

empty

We looked, and our copy holds nothing. That is a finding about our data, not proof that the property or the party has nothing. Some tools go further and say what the emptiness means — a party with no registered disposal comes back empty with a note saying, in as many words, that this is a finding rather than a failure.

partial · incomplete

The lookup did not finish. failed_sections names the parts that did not land, and anything missing from the answer was not checked — not found to be absent. Say the answer is incomplete; never report a number derived from a hop that never ran.

kommune_not_covered

No query ran at all. We hold nothing for that municipality, so the answer says nothing whatsoever about the property. It is never phrased as a result; where_to_check carries a ready link to the municipality's own postliste, and it is offered as help rather than as an apology.

wrong_level

The key cannot answer that question. A borettslagsandel names no matrikkelenhet, and municipal cases are all filed against one — so nothing could be looked up from it. This is not a coverage answer and not an empty one: re-resolve the key and pass the resulting next on, or ask by address.

not_found

The selector matched nothing at all — an address with no unit behind it, a party name with no match. The right move is to ask for the address or the registered name again, never to sweep an area and pick something that looks close.

a refusal

The request itself is turned down, and the refusal explains what to send instead. A fødselsnummer typed into any field of any tool is stopped here, and the refusal does not quote it back — so it reaches neither the model's context nor the audit log. There is no field anywhere on this surface that takes one.

Coverage, and its limits

Different corpora, different edges. Every tool states its own on every answer; this is the short version. Saksinnsyn holds 61 of Norway's 357 kommuner.

Saksinnsyn

Our copy of the municipal postjournal, updated periodically — not the kommune's live archive, so it has its own lag. It also has two edges inside the part we do hold: 4.0 % of the cases carry neither a unitkey nor an address and cannot be reached by any property lookup at all, and 17.8 % of the links between a case and a property were parsed out of free text and never confirmed. The unconfirmed ones sit in uncertain with their own count and are never added to the case count.

Market data

Verified sold transactions and active resale listings. New-builds (nybygg) are not included. Statistics and record searches both run over a window of at most 12 months, and the sold-side window is required rather than optional.

Matrikkel · grunnbok

Nationwide. A plot often has no registered address — that is a fact about the matrikkel, not a gap, and address_status says which of the two you are looking at. Pre-merger municipality numbers are handled for you, so a key's prefix is never edited by hand.

A zero result is never proof of absence. It is a statement about what we hold, and every tool that can come up short carries somewhere else to look.

The controlled values

Two vocabularies are worth knowing before you build a query, because neither is guessable and both are spelled the way the register spells them. Both lists are read from the live schema.

property_type search_properties

eiendom tomt naeringseiendom sameie infrastruktur bygaard borettslag aksjeleilighet

What kind of registered property it is, not what stands on it. eiendom is the ordinary case; tomt is land; sameie and borettslag are the parent that the units inside them belong to; bygaard is an apartment building held as a single property. Mind the spellings — naeringseiendom and bygaard, not næringseiendom or bygård.

naringsgruppe search_properties

landbruk bolig ikke_naering varehandel industri helse_sosial undervisning overnatting_servering offentlig_forvaltning eiendomsdrift transport_lagring bygg_anlegg kultur_fritid annen_tjenesteyting energiforsyning vann_avlop_renovasjon forretningsmessig_tjenesteyting internasjonale_organisasjoner bergverk_utvinning finans_forsikring faglig_teknisk informasjon_kommunikasjon husholdningstjenester

What the buildings on a property are used for, which reaches categories the property type cannot express: landbruk is how you find landbrukseiendommer and gårdsbruk. A property matches when at least one of its buildings falls in the group, because a working farm also has a dwelling and outbuildings — so read bygninger.i_naringsgruppen against bygninger.totalt before describing what a match is.

What your key reaches

Three add-on families sit outside the standard key, and each one is granted on its own. Your own tools/list is the authority on what you have: it returns exactly the tools your key can call.

avm get_avm get_comparable_sales get_price_index

Solgt.no's own valuation model: the estimate, its confidence, and the asking-vs-estimate ratio — in rows, in aggregates, and as something you can filter and sort on. It also unlocks the valuation tools themselves — get_avm, get_comparable_sales and get_price_index — which an ungated key does not see in tools/list at all.

encumbrances get_encumbrances

Heftelser from grunnboken. Without it get_encumbrances is not registered at all: a key that cannot call the tool does not see it in tools/list, and resolve_property leaves the hop out of next to match.

innsyn_text

The text inside a municipal document. Without it you get the journal's metadata and the document titles, which is what get_innsyn_cases returns by default.

The tools

Grouped by the question they answer. Everything below the prose — inputs, types, values, what is required — is read off the running server's own schema.

Taken by every tool intent — the end user's own question, verbatim. It is recorded next to the query so we can see what a human actually asked, and it is stripped of anything that looks like a national ID before it is stored. Omitted from the tables below.

Find the property

Every question about one property starts here. One address, key or finnkode in — the property, its level and the keys the other tools need out — and, with a key in hand, what physically stands on the ground.

Find the property

resolve_property

The first hop for anything about one specific property. Give it an address, a matrikkelnummer, a new_unitkey, a finnkode or a registerenhet id; get back the property, the level it sits at, and the keys every other property tool needs.

When to use it Before get_owners, get_conveyances, get_encumbrances and get_innsyn_cases. It is for one known property — to find a set of properties you do not know yet, use search_properties.

What comes back next is the part you carry on: each entry there is a finished argument object for the tool it is named after. Pass it through unchanged. One address is often many units — Drammensveien 54B is 14 seksjoner — so address_match names the entrances covered and the neighbouring entrances deliberately excluded. address_status separates a resolved address from a property that has none registered, which is a fact about the plot rather than a gap in the data.

Hands off to get_avm get_comparable_sales get_conveyances get_encumbrances get_innsyn_cases get_owners get_price_index get_property_facts get_property_tenancy

↳ adresse-til-eier · ↳ eiendom-til-saker · ↳ eiendom-til-heftelser · ↳ nokkel-uten-fem-ledd

About — needs exactly one of address · new_unitkey · unitkeys · registerenhet_id · finnkode · matrikkel

Field Type Accepted values
address string
kommune string
new_unitkey string
unitkeys≤ 25 items string[]
registerenhet_id integer
finnkode integer
matrikkel object

knr gnr bnr fnr snr

maxTimeMS integer

Find the property

get_property_facts

What is actually there, as the matrikkel records it: the buildings standing on the property with their type, floor area and floors, everything that has been built onto them, any rental listing or parking registered on it, and the date it last changed hands.

When to use it Every other tool on this spine answers what is REGISTERED AGAINST a property — owners, heftelser, overdragelser, kommunale saker. This one answers what stands ON it, which is the question behind "hvor stort er bygget", "hvor gammelt er det" and "har det blitt påbygd". It takes up to 25 keys, copied out of a next block: resolve_property, search_properties and search_commercial_properties all hand it the same five-segment keys. Ask it at whatever level you have — a seksjon or a borettslagsandel is answered from the matrikkelenhet it belongs to, because that is where buildings are recorded, so you do not have to climb to the parcel yourself. get_property_tenancy does not do that and wants the parcel key. For a single home's own floor area use the market tools, not this one.

What comes back answered_from is the first field to read. parent_parcel means the key you asked about is a seksjon or an andel and every number below therefore describes the WHOLE property: a 3 879 m² building is the block, not the flat in it. Area arrives as three labelled numbers rather than one — bruksareal_totalt_m2 is bolig plus annet — and a building the register never measured comes back with areal_status: "ikke_registrert" and nulls, never 0 m², which is the case for over a third of all buildings. etasjer[] breaks that total down; it is never added to it. "Har det blitt påbygd?" is endringer[], and the field that decides the answer is utfall: only gjennomfort was built, bortfalt is an application that was cancelled or a building that is gone, and Ombygging is an internal rebuild that adds no area at all. A property with no registered building is a complete answer — an ubebygd tomt — not a failed lookup. Rental listings come from two sources that are measured to disagree in both directions, so an empty one proves nothing about the other. siste_eierskifte is one date and one omsetningstype, a headline rather than a history — the transfers themselves are get_conveyances. And fredet or sefrak on a building is a real constraint on what an owner may do to it, so say so rather than listing it as a flag.

Reached from resolve_property

↳ hva-star-pa-eiendommen · ↳ er-det-paabygd

Field Type Accepted values
unitkeysrequired≤ 25 items string[]
include_ads boolean
maxTimeMS integer

Find the property

search_properties

Find properties in a municipality, several municipalities, a county or the whole country without knowing which ones: filter by type, seksjonering, bydel or a named område inside the kommune (delområde/grunnkrets — every kommune has them, bydel only six cities do), gårdsnummer, what the buildings are used for, what kind of buildings they are, whether the owner is a company or a private individual, and how many dwellings, owners and square metres of floor area the property has.

When to use it resolve_property answers about one property you can already name; this one produces the set. kommune takes one municipality or a list, fylke a county, and neither means all of Norway — where a property_type is required, because it is the only index that bounds a national query. mode: "count" counts in the database without reading a single row, which is the cheap way to size a question before you ask it, and works at every scope. mode: "rows" is one page and needs a kommune or fylke; so does naringsgruppe, in every mode, while bygningstype has its own national index and works everywhere. mode: "dataset" is the answer to «gi meg alle»: the whole matching set stored as a file the app renders, up to 12 000 rows, with a small envelope back — ask for it instead of paging. Landbrukseiendommer are reached through naringsgruppe: "landbruk"; blocks of flats through bygningstype: "boligblokk" — a family name that expands to the SSB building-type codes on the server (enebolig, tomannsbolig, rekkehus, boligblokk, fritidsbolig, garasje_uthus, kontor, forretning, industri, lager, landbruk_fiske and the rest; a code or a range is accepted too), which is how «bygårder som er boligblokker» is separated from the rekkehus and garages the bygård type also holds. «Minst 4 boligbruksenheter og maks 2 eiere» is min_bruksenheter: 4, max_eiere: 2 in the call — a bound on the registered dwelling count, the registered owners of the matrikkelenhet, or the summed floor area (min_bra/max_bra, m²) — and like naringsgruppe these read every property in scope, so they need a kommune or fylke. How many properties an owner holds is not a filter here — that is get_owner_portfolio, per owner. «I Kvadraturen», «på Lund», «i sentrum» inside a kommune is omrade — a named area matched on the server against the SSB delområde and grunnkrets recorded on nearly every built-on property (the answer says how many in the kommune carry none), which is the sub-kommune level everywhere bydel has nothing (bydel exists only in Oslo, Bergen, Trondheim, Stavanger, Drammen and Bodø). A delområde carrying the word takes the whole delområde; otherwise the grunnkretser that do; and the answer's omrade says which it settled on, with their grunnkretser, so the next call can name the exact ones. A name nothing carries matches nothing and lists the delområder there are — never the whole kommune in the area's place. gnr is the same narrowing by gårdsnummer when the user gives a number. Both need exactly one kommune.

What comes back Rows carrying the complete new_unitkey, the address, the delområde and grunnkrets the property sits in, the distinct building-type codes on the parcel, the dwelling and owner counts, the summed bruksareal with a bruksareal_status saying whether every building was measured, and a plottable point — or just the numbers when you count, or a dataset envelope when you asked for the whole set. Read dekning before you describe a filtered result as complete: a property with no registered building, owner, bruksenhet or measured area cannot be assessed by that filter at all, so the match is a minimum, not the full set — and an upper bound (max_eiere, max_bra) never counts the unregistered as 0.

Hands off to get_owners

↳ landbruk-i-kommunen · ↳ bygaarder-med-faa-eiere

About — needs at least one of kommune · fylke · property_type

mode:"rows" additionally needs a kommune or a fylke; næringsgruppe does too, in every mode, and so do the min/max_bruksenheter, min/max_eiere and min/max_bra bounds; omrade and gnr need exactly one kommune

Field Type Accepted values
kommune string | string[]
fylke string
property_type string | string[]

eiendom tomt naeringseiendom sameie infrastruktur bygaard borettslag aksjeleilighet

seksjonert boolean
bydel string
omrade string | string[]
gnr integer | integer[]
naringsgruppe string | string[]

landbruk bolig ikke_naering varehandel industri helse_sosial undervisning overnatting_servering offentlig_forvaltning eiendomsdrift transport_lagring bygg_anlegg kultur_fritid annen_tjenesteyting energiforsyning vann_avlop_renovasjon forretningsmessig_tjenesteyting internasjonale_organisasjoner bergverk_utvinning finans_forsikring faglig_teknisk informasjon_kommunikasjon husholdningstjenester

bygningstype string | string[]
owner_kind string

company person any

min_bruksenheter≥ 1 integer
max_bruksenheter≥ 0 integer
min_eiere≥ 1 integer
max_eiere≥ 1 integer
min_bra number
max_bra number
mode string

rows count dataset

group_by string

property_type bydel delomrade seksjonert owner_kind kommune

limit1–100 integer
offset0–500 integer
maxTimeMS integer

Find the property

get_nearby_places

What lies around a property, and how far it really is: the three nearest of each kind of place — bus, train, tram, metro, ferry, airport, university, school, kindergarten, supermarket, mall, department store, convenience store, ski resort, shore, lake, city — with the walking and driving distance routed along the actual network, not drawn as a straight line.

When to use it After resolve_property has produced the key: it takes unitkeys (1–10) copied verbatim from resolve_property.next or a search row, and both key shapes work. types narrows to any of the 17 and should be set when the question is about one thing ("hvor langt til T-banen?" → ["metro"]) or about several properties at once. get_property_facts is what stands ON the property; this is what stands AROUND it.

What comes back Three distances per place, and the routed ones are the answer: air_m is the straight line, walk and drive follow the footpath and road network, and they part ways wherever water or terrain is in between — 82 m of air but 855 m on foot to Slependen stasjon is a measured row. walk_detour_ratio (walk ÷ air) makes that visible. There is no public-transport journey time here. Only the three nearest per type are stored, so found says how many exist within radius_m and withheld how many you are not seeing; a subtype question — the nearest barneskole, the nearest Rema 1000 — cannot be settled from it, only what the three nearest schools or supermarkets are. Each type has its own radius_m (bus 3 000 m, shore 1 000, lake 2 000, tram 5 000, metro 10 000, train and ferry 50 000; city unbounded), so found: 0 means none within that radius, never none in Norway. status separates ok, empty (searched, nothing within radius — a real finding) and partial (a key with no enrichment row, named in keys_not_enriched — unknown, not empty; coverage is a minority of all units but ~99 % of active listings). Read updated_at on every row: the corpus is not refreshed daily.

↳ hva-ligger-i-naerheten

Field Type Accepted values
unitkeysrequired≤ 10 items string[]
types string[]

bus train tram metro ferry airport university school kindergarten supermarket mall department_store convenience ski_resort shore lake city

maxTimeMS integer

Who owns it

The registered owner today — from the property, or the other way round, from a name to everything that party holds.

Who owns it

get_owners

Who is registered as owner today, for up to 25 properties at a time — straight off the matrikkel/grunnbok spine.

When to use it For «hvem eier», and for «hvem er hjemmelshaver» too — hjemmelshaver is the grunnbok's own word for the party this returns, not a separate one. This is the present tense. Who owned it before, and what was paid, is get_conveyances. Going the other way — from a name to the properties — is resolve_owner followed by get_owner_portfolio.

What comes back Name, share, ownership form and a safe identification number: a company's organisasjonsnummer in full, a private individual's national ID never. For a company you also get organisasjonsform, status and one level of beneficial ownership from the aksjonærregister. Rows are CURRENT holders only: every row is checked against the grunnbok's own transfers of that property, a party recorded as having sold it is left out and counted in owners_retired, and a holder whose purchase is on record carries gjeldende_fra, the tinglysingsdato — absent when the holding predates the digital grunnbok, never a guess. owners_status carries four different answers, and owned_at_unit_level is the one that trips people up: a sameie or borettslag has no owner of its own, because it is owned seksjon by seksjon, and owned_units.unitkeys says where to ask instead.

Reached from resolve_property search_properties search_property_holdings

↳ adresse-til-eier · ↳ eier-pa-feil-niva

About — needs exactly one of new_unitkey · unitkeys

Field Type Accepted values
new_unitkey string
unitkeys≤ 25 items string[]
include_shareholders boolean
maxTimeMS integer

Who owns it

resolve_owner

A name in, the parties that actually exist out. It resolves companies and private individuals alike, because grunnbok ownership is public record.

When to use it Whenever you have a name rather than an identifier. An organisasjonsnummer cannot be derived from a name, so resolve it here first; private individuals resolve the same way, because grunnbok ownership is public record.

What comes back Read resolution first, because a name is not an identity and that is the normal case: unique (one party, next is filled in), ambiguous (several — next is empty on purpose, so ask which), narrowing_required (too many private individuals to list; ask for a municipality) or not_found. Each candidate carries holdings.total and holdings.kommuner so the choice can be put to a human meaningfully. A name written with initials («Andreas S. Wöllert») is expanded against the register when no exact spelling matches. A candidate marked has_disposals holds nothing today but used to — a FORMER owner, whose next aims get_owner_history instead of the portfolio: the call for «hva har de solgt, og hva fikk de for det». Zero holdings plus that hop means «eier ingenting NÅ»; follow it before concluding anything about ownership, and name the last sale.

Hands off to get_owner_history get_owner_portfolio

↳ navn-til-portefolje · ↳ avvist-fodselsnummer

Field Type Accepted values
namerequired string
kommune string
maxTimeMS integer

Who owns it

resolve_company_group

A group name in, every company in the konsern out — and what they all own, counted as one portfolio. A Norwegian property group is a holding company plus a fan of single-purpose companies whose names carry no trace of it; the portfolio is the union of all of them.

When to use it Whenever a user names a property company, a landlord or a chain and asks what "they" own. resolve_owner answers a different question — which single party carries this name — and live it resolves HEIMSTADEN AS, which owns nothing directly; answering from that alone reports 0 properties for a landlord holding thousands. If you are about to say "de eier ingenting" or to ask for a subsidiary's organisasjonsnummer, this is the tool you wanted. It takes one name, matched as a prefix on the company register and on the registered group parent. The properties themselves are the same call: mode: "rows" lists them a page at a time with the holding company on every row, mode: "dataset" stores the whole list as a file the calling application renders — «vis alle eiendommene til Olav Thon» is one dataset call, never one get_owner_portfolio per company — and kommune scopes the count and the list alike.

What comes back Two levers, both reported: via: "navn" is a company whose own name carries the group name, via: "konsern" one whose registered group parent does while its own name gives no hint — listing only the first understates the portfolio. group.total is the whole group's property count (parcels + sub_units) summed over every company matched, and group.holding_companies how many of them hold anything at all. A null konsern_topp_orgnr is normal: the parent is foreign and has no Norwegian organisasjonsnummer. matching says whether spelling was forgiven — under exact an empty answer may be a typo. Read the notes before summing: a broad name can match companies that merely share a prefix, and the notes say so. Every company row carries next.get_company and next.get_owner_portfolio, so the drill-down is a copy, never a number assembled by hand. In rows mode properties carries the page and total the whole list, each row a portfolio row plus eier; a dataset answers with the envelope, its coverage.kilde_dekning naming how many companies the group had and how many hold property.

Hands off to get_company get_owner_portfolio

↳ hele-konsernet

Field Type Accepted values
namerequired string
mode string

companies rows dataset

kommune string
page≥ 0 integer
page_size integer
maxTimeMS integer

Who owns it

get_company

Everything the registers hold about one company, by organisasjonsnummer: master data, the latest annual filing, the dated shareholder register (2020–2025), current board and auditor roles, its subsidiaries, and how much property it holds.

When to use it After resolve_company_group or resolve_owner has produced the orgnr — those two resolve a name, this is the drill-down for the company itself. Its next block carries ready-made calls for the Norwegian parent and up to ten subsidiaries, so a corporate group can be walked hop by hop without assembling a single number by hand.

What comes back aksjonaerer is dated: one entry per register year, newest first, each carrying register_aar, and the register covers 2020 through 2025 — nothing older exists. Holder identities are re-derived rather than read, because the source types every holder without a Norwegian organisasjonsnummer as a person, foreign companies included: holder_form separates selskap, privatperson, utenlandsk_selskap and ukjent, and ukjent means undetermined rather than a private person. A person is identified by name and birth year only. regnskap is the latest filing rather than a series, so no trend can be read from it, and its own status separates a company that files nothing from a filing we could not fetch. A null konsern.topp_orgnr next to topp_er_utenlandsk: true means the group parent has no Norwegian organisasjonsnummer — the normal shape for the large landlords, not a gap.

Hands off to get_owner_portfolio

Reached from get_owner_portfolio resolve_company_group

↳ selskapskortet

Field Type Accepted values
orgnrrequired string
maxTimeMS integer

Who owns it

get_owner_portfolio

Everything a party is registered on right now, paged, with the whole portfolio counted even when only a page is shown.

When to use it Takes an organisasjonsnummer or a grunnbok_id — both come from resolve_owner. It answers "what does X own", which get_owners cannot.

What comes back total is the whole portfolio, shown is this page — never report the page as the total. Rows are CURRENT holdings: each is checked against the grunnbok's own transfers of that property, a property the party is recorded as having sold is left out and counted in properties_retired, and a row whose purchase is on record carries gjeldende_fra, the tinglysingsdato; when only a page was checked, total is a ceiling and the note says so. A seksjon or borettslagsandel is recorded on the parent matrikkelenhet's document, and read_from says so; that parent's own owner is a different party and is not part of this portfolio. For a party addressed by grunnbok_id, selskaper adds what the aksjonærregister records them as holding shares in — a yearly snapshot, dated by synced_at, each company with how many properties it is registered on and its own next.get_company and next.get_owner_portfolio hops, which is how «direkte eller indirekte» is answered without assembling an organisasjonsnummer by hand. Its section status keeps three answers apart: holdings, a party the register indexes and lists nothing on (empty), and a party the register does not reach at all (not_found) — the last is never «eier ingen selskaper». A company addressed by orgnr skips it; its holdings are get_company's datterselskaper.

Hands off to get_company

Reached from get_company resolve_company_group resolve_owner

↳ navn-til-portefolje

About — needs exactly one of orgnr · grunnbok_id

Field Type Accepted values
orgnr string
grunnbok_id integer
kommune string
property_type string

eiendom tomt naeringseiendom sameie infrastruktur bygaard borettslag aksjeleilighet

page≥ 0 integer
page_size integer
mode string

rows dataset

maxTimeMS integer

Who owns it

get_company_financials

The filed annual accounts for up to 25 companies in one call: revenue, operating result, net result, equity, total debt, total assets and the equity ratio. Built for portfolios, where the question is how solid a fan of single-purpose companies is rather than how one of them did.

When to use it After search_companies, resolve_company_group or any tool that hands back organisasjonsnummer — copy next.get_company_financials through unchanged. get_company is the drill-down for ONE company and carries the shareholder register, board roles and subsidiaries beside the accounts; this is the accounts alone, in bulk. It takes nine-digit organisasjonsnummer only: an eleven-digit number is a fødselsnummer and is refused rather than looked up.

What comes back A SNAPSHOT, not a series, and the answer says so before anything else: 440 346 of the 444 803 companies in the source have exactly one filed year, so no trend, growth rate or direction can be read from these figures however they are arranged. aar is the FISCAL year, verified against the filed period, and it DIFFERS BETWEEN COMPANIES — filing is staggered, with 416 413 rows on FY2025, 25 155 on FY2024 and 3 589 still on FY2023 — so it rides every company rather than the answer, and regnskapsaar counts the spread. foreldet_regnskap flags a company three years or more behind the calendar year, which means at least one whole filing cycle was missed; it is a soft signal and never a conclusion, because a dormant company looks identical. omsetning_kilde separates a filed revenue figure from a zero the accounting identity proves (Brønnøysund omits the field instead of writing 0) from a genuine unknown, which is what keeps a property SPE with no operating revenue visible as the ordinary thing it is rather than as a warning. Every figure carries its own valuta — 1 205 filings are in USD, EUR, SEK or one of eleven others — so nothing may be added to a kroner total without checking it. The debt split is deliberately absent: 97.7 % of companies file abbreviated accounts and long-term debt is missing from over half of them, which is exactly where a landlord's mortgage would sit, so sum_gjeld carries the total and an absent long-term figure never means debt-free. A company with no numbers is not a failed lookup — regnskap_status says which of four it is: filed but not yet mirrored, does not file at all, could not be fetched, or not assessed.

Reached from search_property_holdings

Field Type Accepted values
orgnrrequired≤ 25 items string[]
maxTimeMS integer

What it has been through

Registered transfers: who sold to whom, when, and for how much — and the same question asked of a party rather than a property.

What it has been through

get_conveyances

Every tinglyst overdragelse on a property, newest first: date, omsetningstype, vederlag, dokumentavgift, fellesgjeld where recorded, and the buyers and sellers.

When to use it After resolve_property. A parcel and its seksjoner have separate histories and neither contains the other, so ask at the level the question is about.

What comes back A transfer without a price is normal — gave, arv, uskifte, fusjon and old registrations carry no vederlag. It comes back as price: null and is never a sale for 0 kroner. Every amount names its currency. totals counts for you, including the split by omsetningstype, so nothing has to be summed across rows. And a price is what someone paid on a date; it is not a valuation.

Reached from resolve_property

↳ overdragelser

Field Type Accepted values
unitkeysrequired≤ 25 items string[]
limit≤ 50 integer
include_parties boolean
maxTimeMS integer

What it has been through

search_conveyances

The screen the single-property history cannot do: every tinglyst overdragelse in a kommune of a given kind in a date window — arv, tvangssalg, gave, fritt salg — one row per transfer, newest first, with the property, its address, the price where one was recorded and the parties as the grunnbok names them.

When to use it For «finn nylig arvede boliger i Oslo», «dødsbo i Frogner siste måned» or «hvor mange tvangssalg i Bergen i juli». get_conveyances is the history of one property you already hold the key to; this finds the properties from the kind of transfer. The register has no «arv» code — an inheritance is tinglyst as Skifteoppgjør (the estate settled and passed to the heirs) or Uskifte (the surviving spouse took it over undivided), and omsetningstype: ["arv"] selects both. The cost is the kommune times the window: the scan rides a kommune-plus-date index, but every document with a transfer in the window is read whole. fra is required, at most 366 days fit one call, and next.search_conveyances carries the previous period so a decade is walked a year at a time. mode: "count" is exact and never capped, with group_by over omsetningstype, eiendomstype, kommune or bydel; mode: "rows" pages up to 5 000 transfers; mode: "dataset" stores the whole window as a file the calling application renders. «Tvangssalg i Bergen» is omsetningstype: ["tvangssalg"] here: the register holds the forced sales that were tinglyst, and a sale only announced or begjært is in no register this surface reads — the answer says so beside the list. An utlegg is not a tvangssalg; utlegg are read per property, in get_encumbrances.

What comes back One row is one TRANSFER, so the same property can appear twice in a window — antall_eiendommer counts the unique ones and a lead list de-duplicates on new_unitkey. Dates are tinglysingsdato, which can lag the agreement by weeks. A transfer without a price is normal (arv, gave, uskifte and fusjon carry no vederlag), comes back as price: null and is never a sale for 0 kroner; a price filter keeps only transfers with a recorded figure. On an arv row the buyers ARE the heirs, named as the grunnbok names them, each with a kind; no fødselsnummer is ever returned. address is resolved through the same resolver resolve_property uses and address_status says why it is null when it is — the key is always complete. next carries get_conveyances and get_owners for the page's properties, and the previous window for this tool.

Field Type Accepted values
kommunerequired≤ 10 items string[]
frarequired string
til string
omsetningstype≤ 13 items string[]

uoppgitt fritt_salg gave ekspropriasjon tvangssalg uskifte skifteoppgjor opphor_av_samboerskap annet skifteoppgjor_ved_samlivsbrudd fusjon_fisjon arv samlivsbrudd

eiendomstype string[]

matrikkelenhet festegrunn seksjon borettslagsandel

bydel string
min_pris≥ 0 integer
max_pris≥ 0 integer
include_parties boolean
mode string

count rows dataset

group_by string

omsetningstype eiendomstype kommune bydel

page≥ 0 integer
page_size integer
maxTimeMS integer

What it has been through

get_owner_history

What a party used to hold, and whether they actually let go of it.

When to use it The past-tense twin of get_owner_portfolio. Same party selector, opposite question.

What comes back holding_status is checked against the current-owner index: sold means they are out, still_owner means they are not and must never be described as a former owner. A party with no registered disposal comes back empty — that is a finding, stated plainly, not a lookup that failed.

Reached from resolve_owner

↳ tomt-er-et-funn

About — needs exactly one of orgnr · grunnbok_id

Field Type Accepted values
orgnr string
grunnbok_id integer
kommune string
from_year integer
to_year integer
page≥ 0 integer
page_size integer
mode string

rows dataset

maxTimeMS integer

What is registered on it

Grunnboken's encumbrances — pant, servitutter, anmerkninger — and who holds the right.

What is registered on it

get_encumbrancesadd-on

What is registered against a property in grunnboken — pant, servitutter, anmerkninger and the rest of the 16 heftelse types, grouped, with each row's rettsstiftelsestype, amounts, free text and rettighetshavere.

When to use it It takes registerenhet_ids and level, and both come from resolve_property — there is no address form. A parcel and its seksjoner have different heftelser and neither contains the other: an empty answer at parcel level says nothing about the apartments. «Utlegg», «tvangsforretning» and «tvangspant» are this tool, one property at a time — there is no area-level list of utlegg in any register this surface reads; completed tvangssalg over a kommune are search_conveyances.

What comes back totals counts each kind for you — pant, tvangsforretninger, servitutter, anmerkninger, historiske — plus pant_total, because amounts must not be summed across rows by hand. An utlegg (utleggsforretning or utpanting) is a Tvangsforretning, counted in antall_tvangsforretninger and never in the pant figures: it is a claim against the owner, not a mortgage on the property. A decided tvangssalg is not in this tool at all, and a completed one is a conveyance — ask get_conveyances for that. Utlegg are covered both ways: on the property's own rett, and on a single co-owner's andel — nearly half are the second kind, and those rows carry burdens_andeler with the share and are counted in antall_tvangsforretninger_paa_andel, so report them as a claim against that co-owner rather than against the whole property. A heftelse of some other type registered only on an andel is still out of reach, so a zero for pant or servitutter is near-complete but not absolute. Every amount is reported with its currency named, and a Pant denominated in something other than kroner is deliberately kept out of pant_total. Rettighetshavere are named as the grunnbok records them; each carries a kind, and "unknown" means the identity hop was skipped or capped, not that the party is private.

Reached from resolve_property

↳ eiendom-til-heftelser · ↳ utlegg-paa-andel

Field Type Accepted values
registerenhet_idsrequired≤ 25 items integer[]
levelrequired string

unit parcel

include_rettighetshavere boolean
limit≤ 200 integer
maxTimeMS integer

Municipal cases

The municipality's own journal for the property, with the documents attached to each case. Coverage is partial, and the tool says so on every answer.

Municipal cases

get_innsyn_cases

The municipality's own journal for a property: byggesaker, delesaker, seksjonering, tilsyn, konsesjonsfrihet, ferdigattest, plansaker — newest first, each with the documents attached to it.

When to use it Two ways in, and exactly one of them per call: unitkeys + level copied from resolve_property, or address (+ kommune) for a place someone named in words. The address path runs the same resolver resolve_property uses and adds the matrikkelenhet for you, so it is a complete answer in one call.

What comes back Case type is inferred from the title, because the journal records none — present it as a reading of the titles, never as the municipality's own classification. Documents come with each shown case in three distinct states: openable (we hold the file), listed_only (the journal names documents we hold no file for — still reachable at the municipality, and withheld says why) and none. A bulk filing — five or more cases registered on one day under one title — is collapsed into a single row with bulk: { count, saksnummer[] }, so say how many the row stands for. Anything a types filter held back is counted in counts.set_aside and must be mentioned. A plan question is types: ["plansak"]: the answer then carries kommune_coverage.plansaker — how many of that kommune's cases in our copy read as plan cases at all — and a note saying that a reguleringsplan is filed on the plan, not on each property it covers, so an empty page is never «ingen reguleringsplan gjelder».

Reached from resolve_property

↳ eiendom-til-saker · ↳ kommune-ikke-dekket · ↳ feil-niva

About — needs exactly one of unitkeys + level · address

Field Type Accepted values
unitkeys≤ 25 items string[]
level string

unit parcel

address string
kommune string
from_year1800–2100 integer
types string[]

byggesak ferdigattest seksjonering deling_oppmaaling plansak tilsyn vann_avlop konsesjon administrativt

limit≤ 100 integer
mode string

rows dataset

maxTimeMS integer

Businesses and premises

Which properties a kind of business operates from — and the same question from the other end: which businesses are registered on one property, who runs them, and who owns the building they stand in. Plus the two set tools that answer about the businesses THEMSELVES rather than about a property: which companies sit in a catchment and how big they are, and the registered parking around them.

Businesses and premises

search_commercial_properties

Every property a kind of business operates from, with who runs the shop, who owns the building and who owns them. search_properties finds properties by what the register records about the property itself; this one finds them by the business standing on it.

When to use it The way in is what the business DOES or the name over its door; a question that starts from who OWNS the næringseiendommer — SPV and portfolio structure, related-party tenants, «hvem eier mest» — belongs to search_property_holdings instead. Two ways in, at least one of them required, and they are different questions rather than two spellings of one. naeringskode is what the business DOES — the register's own NACE code: grocery 47.11, pharmacy 47.73, car dealership 45.11, gym 93.13 — while brand is the name over the door. Nationally 47.11 matches 6 140 businesses on 4 815 properties, and 2 031 of those properties carry none of the named chains, so "every grocery shop" and "every chain shop" are different sets with different answers; passing both intersects them. mode: "count" is the one that answers a national HOW MANY — businesses, properties, and the distribution by kommune or kjede — in about a second. mode: "rows" returns the property rows a page at a time and requires a kommune or a fylke: a national row extract is around 4 800 properties, which no single response can carry, so it is refused rather than paged. mode: "dataset" is the route for the complete list, national included: it runs the whole scope, stores the full row set as a dataset the calling application renders directly, and returns a small envelope — columns, counts, a 5-row preview and the caveats — from which the rows must never be retyped. A caller without a dataset-rendering surface assembles the same list by walking the 15 fylker, each call bounded and its total exact. group_by: "leieforhold" is the one distribution that costs something — it has to resolve the deed and both ownership chains for every property in scope — so it runs in count mode inside a kommune or fylke, in a second or two, and is refused nationally. It covers the whole scope; the tenancy_summary on a rows answer counts only that page. And group_by belongs to counting: a rows answer refuses it rather than quietly ignoring it, and a dataset — which carries the rows themselves — refuses it too.

What comes back Five parties, kept apart. The question a commercial answer exists to settle is whether the operator and the landlord are the same interest, and that cannot be asked once they have been flattened into one "owner": driftsselskap runs the shop, leietaker_kjede is the brand over the door, morselskap is the operator's parent, spv is the party holding the deed, and overste_eier sits at the top of that party's share chain. leieforhold is derived from those ownership links rather than read from a lease — there is no commercial tenancy register behind it — and its five values are five different statements: selveier (the operator's parent IS the registered owner), nærstående (different legal entities, but both chains pass through the same company, which naerstaende_via names), ekstern utleier (both chains resolved and share nothing), eierkjede uoppløst (the chain could not be resolved at all — the absence of a finding, and not an arm's-length landlord) and ukjent (no registered owner to start from). overste_eier carries the date its source was last checked and an entydig flag; false means the chain ends in several equal holders, so the name shown is one of them rather than an established controlling owner. tied_holders counts the level-pegged holders when entydig is false; it is a number, not a list of names. On is_top and no_owner_by_type the navn is empty by design, because the top is the party already named in spv. It also carries a status, and only one of its four values is a gap: resolved names an owner above the landlord, is_top means the landlord IS the top — a private person holding the deed, or a public body, since nothing owns a kommune — no_owner_by_type means nothing owns it by construction (borettslag, sameie, stiftelse, samvirke, forening), and only unresolved is genuinely unknown, with grunnlag naming the ground in each case. evidens names which registry field settled it — hjemmel when the matrikkel recorded a fødselsnummer, so the holder is a natural person and the chain ends there, organisasjonsform when Brreg's own form code answers it, konsernrollup when a chain was resolved, and null when nothing did. Every one of those is a registry field: ownership is never inferred from a næringskode, a company name or an address, so an AS filing «Aktiviteter i borettslag og boligsameier» stays unresolved rather than being assumed resident-owned — it may equally be owned by a kommune or a holding company. Two grounds are not the same claim: ikke_i_aksjonaerregisteret means the share register does not hold the company, while eierkjede_ikke_slatt_opp means this particular answer did not walk it — a mode: "dataset" list reads the maintained rollup and skips the walk, and on the nationwide grocery list 177 of the 259 companies left unresolved are in fact in the register with shareholders on file. Measured nationwide on dagligvare, four of every five rows that used to read «Ukjent» were one of the first three, so treating the status as a single unknown throws the answer away. bra.m2 is every building on the property and not the shop's own floor area — a grocery on the ground floor of a block of flats reports the block. And read dekning before calling a list complete: a business with no matrikkel link is missing from the rows rather than absent from the market, which is 869 of the 6 140 in the national grocery count below. Each party that files accounts carries them under regnskap — the landlord (spv), whoever sits at the top of its chain (overste_eier) and the operator's parent (morselskap), but never driftsselskap, because a sub-unit files none of its own. That is what answers whether a landlord can carry the building: egenkapitalandel_prosent with the raw egenkapital and sum_eiendeler behind it, omsetning and aarsresultat, and negativ_egenkapital for the case that matters — on one page of Bergen groceries, four landlords report equity below zero, one of them at −188 % of assets. Read four things before quoting a figure. regnskap is an ARRAY, one entry per fiscal year, each carrying its own aar: today almost every company has exactly one year, so there is no trend to read and none is offered. aar is the FISCAL year and not the filing year — 183 companies already file a 2026 period that runs to February or March — so periode is what makes two companies' years comparable. omsetning_kilde separates a filed figure from a zero the accounting identity implies (Brønnøysund omits the field rather than writing 0, in 84 374 documents) from a genuine unknown, which is how a dormant holding company stays visible instead of rendering as a dash. And status is about the FILING, not about us: leverer ikke is a registered fact about the company, ikke hentet is a failure at Brønnøysund that says nothing about it, and the two must not be read alike. The figures are always the company's own — the source holds no consolidated accounts at all, so a parent's balance sheet is not its group's. A mode: "dataset" answer carries none of that row shape inline. It is a small envelope: dataset_id, the stored object's path, created_at, the resolved scope, the nine columns (matrikkelnummer · adresse · leietaker(e) · postnummer · kommune · øverste eier · hjemmelshaver (SPV) · tomtestørrelse · BRA), row_count, coverage — with kolonner_med_hull naming each column that has holes and how many — a preview of at most five rows, and merknader. The merknader are part of the answer, not debug output: they carry the same traps in dataset form (BRA is the whole building, a samvirke has no top owner, tenancy is inferred), and the businesses without a matrikkel link are counted in the envelope and named one by one in the stored manifest — never dropped silently.

Hands off to get_property_tenancy

↳ naering-eller-kjede · ↳ butikk-til-utleier · ↳ leieforhold-i-kommunen · ↳ hele-landet-som-rader

About — needs at least one of naeringskode · brand

mode:"rows" additionally needs a kommune or a fylke

Field Type Accepted values
naeringskode string
brand≤ 12 items string[]
kommune string
fylke string
mode string

count rows dataset

group_by string

kommune kjede leieforhold

page≥ 0 integer
page_size integer
maxTimeMS integer

Businesses and premises

search_companies

The one set tool that returns COMPANIES rather than properties: which legal entities are registered in a catchment, how many people they employ, what they do, how old they are and whether they can be reached. It never touches the matrikkel and never says who owns a building.

When to use it Reach for it on a question about businesses — the tenant pool for an office building, the employer mix of a kommune, how many firms of a given kind exist and how big they are. search_properties finds properties by their matrikkel attributes, search_commercial_properties finds properties by the business standing on them, and search_property_holdings finds næringseiendommer by who owns them — all three answer with a property. This one answers with the company, so if the user wants buildings it is one of the other three. At least one indexed selector is required in every mode — a næringskode, a geography, or an organisasjonsform — because employee count, age and status carry no index and would turn the query into a scan of the whole 1.17-million-row enhetsregister; the refusal names the routes that work. mode: "count" answers nationally, with group_by over kommune, næringskode, size band or legal form. mode: "rows" returns the companies a page at a time and requires a geographic scope. mode: "dataset" runs the whole scope and stores the full set as a file the calling application renders, returning a small envelope the rows must never be retyped from. kommune takes several municipalities at once, so a travel-to-work area is one call rather than six. The aarsresultat filter carries the profitability screening: it keeps only companies whose own newest filed year ran at a profit or a loss, excludes the companies with no filed figures as unknown — never unprofitable — and discloses how many those are in the regnskap_dekning block. rangering is the ordering beside it, and the only route to «de største underskuddene i Norge». It drives from whichever side is selective: inside a scope that fits the candidate ceiling — Ringerike, a narrow næringskode — the accounts of every candidate are read and the order is exact; nationally, or over a scope past the ceiling, it turns the query round and drives it from the accounts register instead — the deepest results in the country first, the company register read only for the ones that survive. No geography is required, and the answer is honest about its edge: rangering_dekning.grunnlag says which side drove, and a window carries its size and the terskel in kroner it was cut at, so the reader can see that this is the top of a ranking rather than a census. Every company in one place, ordered or not, is the same question asked without rangering and with a kommune.

What comes back Read dekning before describing any count, because it is the difference between a floor and a market size: only 12.3 % of active AS in a typical catchment carry an employee figure at all, so an employee-filtered answer says nothing about the other 87.7 % and the block states how many those are. A missing antall_ansatte is UNKNOWN and never zero — the register omits the field rather than writing 0, and its own harRegistrertAntallAnsatte flag stands true for 85 359 active AS with no figure behind it, which is why this tool never filters on that flag. The figure that is present is the whole LEGAL ENTITY's payroll and not the address's: Vinmonopolet reads 3 004 employees on one unit standing behind 357 shops, so any question about how many people work at a place needs single_site, which keeps only companies with at most one registered underenhet and, measured over a six-kommune catchment at 200 employees and up, cuts 652 companies to 126. That filter is a fact about the REGISTRATION rather than a site survey — public bodies and security firms under-register their sub-units and pass it — and antall_underenheter is on the row so the claim can be checked. naeringskode_preset: "office_tenant" removes the codes whose staff are deployed somewhere else entirely — bemanning, vakt, renhold and omsorg — because a vikarbyrå with 1 471 employees has a handful of desks; over the same catchment it drops roughly twenty phantom tenants. forretningsadresse is the company's registered seat, which is a company fact and not a property lookup: a firm may operate from somewhere else, and the answer must not present the seat as premises.

About — needs at least one of postnummer · kommune · fylke · naeringskode · naeringskode_preset · organisasjonsform · rangering

mode:"rows" additionally needs a kommune, fylke or postnummer — unless `rangering` orders the answer, which bounds it instead; and `rangering` does not satisfy mode:"count", which orders nothing and still needs one of the indexed selectors

Field Type Accepted values
naeringskode≤ 20 items string[]
naeringskode_unntak≤ 20 items string[]
naeringskode_preset string

office_tenant kontor butikk lager industri undervisning servering_overnatting helse_omsorg blandet

kommune≤ 30 items string[]
fylke string
postnummer≤ 200 items string[]
min_ansatte≥ 0 integer
max_ansatte≥ 0 integer
single_site boolean
organisasjonsform≤ 20 items string[]
status string

aktiv konkurs under_avvikling alle

min_alder_aar≥ 0 integer
max_alder_aar≥ 0 integer
has_contact boolean
aarsresultat string

overskudd underskudd

rangering string

storste_underskudd storste_overskudd

mode string

count rows dataset

group_by string

kommune naeringskode ansatte_intervall organisasjonsform

page≥ 0 integer
page_size integer
maxTimeMS integer

Businesses and premises

search_property_holdings

Næringseiendommer by their ownership and tenancy profile: one row per matrikkelenhet with the registered owner, a derived profile of that owner (eiendomsselskap, SPV, konsern, portfolio size, legal form), how many businesses stand registered on the property, related-party presence and a local rent estimate.

When to use it The ownership-first way into commercial property. search_commercial_properties starts from what a business DOES and finds its properties; this one starts from who OWNS the property and what stands on it, so «hvem eier næringseiendommene her», «eiendommer eid av SPV-er eller store porteføljer» and «eiendommer der leietakerne er nærstående til eieren» all route here. mode: "count" answers nationally and uncapped — the whole corpus is 72 511 properties — with group_by over kommuner or the twenty biggest owners; mode: "rows" returns the properties, biggest registered floor area first, and requires a kommune or fylke; mode: "dataset" stores the complete set as a file the application renders.

What comes back Three measured traps ride every answer. Tenant counts are ADDRESS REGISTRATIONS, never lease contracts: a business counts as standing on the property because it is registered at one of its addresses, so a kontorhotell or c/o-address reads as hundreds of tenants — one Oslo cluster carries 1 844 — and a high address_org_count on the row is what exposes such clusters. Tinglyst leie is the opposite blind spot, present on ~3 % of the corpus and skewed old, so its absence never means an empty building. The owner profile is DERIVED — er_eiendomsselskap reads the owner's næringskode, er_spv the single-purpose shape, portefolje_antall the owner's properties in this register — screening signals rather than legal facts. And 26 % of the corpus carries no registered næringsareal, so an areal filter is a floor over that blind spot and the unmeasured sort last rather than being dropped. Owners are always juridiske (orgnr) — a private person never appears — and the full grunnbok ownership picture is the get_owners hop each row hands on.

Hands off to get_company_financials get_owners get_property_tenancy

Field Type Accepted values
kommune≤ 30 items string[]
fylke string
eiendomsselskap boolean
spv boolean
i_konsern boolean
eier_form≤ 20 items string[]
min_portefolje≥ 0 integer
max_portefolje≥ 0 integer
min_leietakere≥ 0 integer
max_leietakere≥ 0 integer
har_naerstaaende boolean
min_naeringsareal_m2≥ 0 integer
max_naeringsareal_m2≥ 0 integer
mode string

count rows dataset

group_by string

kommune eier

page≥ 0 integer
page_size integer
maxTimeMS integer

Businesses and premises

search_parking_facilities

The 22 296 parking areas Statens vegvesen holds a registration for, each with its capacity, its charging and accessible spaces, and the operator behind it — resolved through the register of 585 parking providers and on into the company register for that operator's næringskode and size.

When to use it For "how many parking spaces are there here", "who runs the parking in this kommune" and "which car parks have charging points". It is a register of areas, not of ownership: private parking with no registration duty is simply not in it, so an empty answer proves nothing about whether parking exists. mode: "count" answers nationally with group_by over kommune, operator, area type or the operator's næring; mode: "rows" requires a geographic scope or an operator; mode: "dataset" stores the whole scope as a file the application renders.

What comes back Three things decide whether a number from here is right. Over half the corpus — 11 485 of 22 296 rows — is a deactivated registration, so aktiv defaults to true and a deactivated row must never be summed into current capacity. The corpus records NO kommune: every area carries a postnummer, a poststed and a point and nothing else geographic, so a kommune filter is resolved through the postal-code table, an area whose postnummer is not in that table comes back with a null kommune and is counted rather than dropped, and a postnummer straddling a boundary follows the table's assignment. And the operator is often not a company the register knows — operatorer reports the three buckets instead of hiding them: resolved directly as a legal entity, resolved through an underenhet number to its parent ("ONEPARK AS AVD HOVEDKONTOR" is a sub-unit number, not a company), or absent from the company register entirely, which is mostly kommuner deleted in the 2020 reform and wound-up operators rather than a lookup failure. Næringskode 52.212 is not the sector: nationally 69 of the 585 registered operators file it, against 131 filing generell offentlig administrasjon, because most parking in Norway is run by municipalities in-house — so "how many parking operators are there" answered off 52.212 alone misses four fifths of them. Area type decides what a count means: kerbside registrations are 12 181 of the rows and carry a handful of spaces each, so a bare area count is dominated by them while a capacity question is usually about the 8 975 delimited lots and 1 140 structures.

Field Type Accepted values
kommune≤ 30 items string[]
fylke string
postnummer≤ 200 items string[]
operator string
min_plasser≥ 0 integer
max_plasser≥ 0 integer
type string[]

LANGS_KJOREBANE AVGRENSET_OMRADE PARKERINGSHUS

min_ladeplasser≥ 0 integer
min_forflytningshemmede≥ 0 integer
innfartsparkering boolean
aktiv boolean
mode string

count rows dataset

group_by string

kommune operator type operator_naering

page≥ 0 integer
page_size integer
maxTimeMS integer

Businesses and premises

get_property_tenancy

One property in, the businesses registered on it out — each with its næringskode and its parent company — together with the party holding the deed and whether the two are the same interest. The single-property inverse of search_commercial_properties.

When to use it It takes matrikkelnummer, up to 25 per call, copied out of a next block rather than typed: resolve_property.next hands the same five-segment keys to get_owners and get_property_facts, and search_commercial_properties.next.get_property_tenancy is the set that search just found. Ask it at parcel level — businesses are registered against the matrikkelenhet, so a seksjon key finds nothing and comes back funnet: false rather than climbing to the parcel by itself. It answers about every registered business, not only retail, which is what "who is in this building" means when the building is the thing being bought. For the grunnbok owner on its own use get_owners; for the buildings use get_property_facts.

What comes back One row per key, matched or not. virksomheter names the businesses registered at the property in Enhetsregisteret — a registration, not a lease: a company can be registered at an address it does not trade from, and a tenant that never registered is not in the list at all. virksomheter_totalt counts every registration on the property, so say how many the named ones stand for. The owner side is the same five roles and the same inferred leieforhold as the set query, read the same way — eierkjede uoppløst is a chain we could not resolve, not a landlord established to be external. overste_eier carries the same typed status as the set query, and only unresolved of its four values is a gap: is_top and no_owner_by_type are answers, with grunnlag naming the ground and evidens the registry field that settled it. On those two the navn is deliberately empty — the top IS the party in spv, so read the name from there rather than showing a blank as an unknown owner — and tied_holders is a count of level-pegged holders, never a list of their names. bra.m2 is every building on the property, which for a shopping centre is the centre rather than the unit. The landlord, its ultimate owner and each occupant's parent company carry their filed accounts under regnskap, read exactly as in search_commercial_properties: a year-by-year array, each entry carrying its own fiscal aar and periode, with egenkapitalandel_prosent as the solvency number and omsetning_kilde separating a filed revenue from an implied zero from an unknown. The occupants themselves do not carry accounts — a sub-unit files none, its parent does.

Reached from get_property_occupants resolve_property search_commercial_properties search_property_holdings

↳ hvem-sitter-i-bygget

Field Type Accepted values
unitkeysrequired≤ 25 items string[]
mode string

rows dataset

maxTimeMS integer

Businesses and premises

get_property_occupants

The businesses registered at one property, in one cheap indexed hop: name, orgnr, branch-or-company, parent orgnr, and whether the registration belongs to the property's own registered owner or to someone else.

When to use it Reach for it when the question is "hvem er registrert her" and nothing more — it is the light half of get_property_tenancy, which answers the same list and then resolves konsern, eierkjede and regnskap on top. It takes matrikkelnummer, up to 25 per call, copied out of a next block; businesses are registered against the matrikkelenhet, so ask at parcel level. When the follow-up is ownership or accounts, every property row hands its keys onward in next.get_property_tenancy.

What comes back One row per key. Each registration carries relationship: owner_occupier is registered at the property AND matched to its registered owner; presumed_tenant is registered there and NOT the owner — which suggests a tenancy and does not establish one. A registration is an Enhetsregisteret address, not a lease: a company can be registered where it does not trade, and a tenant that never registered is missing entirely. confidence scores the address match; rows under 0.8 are flagged in the notes and must be qualified. Totals count every registration even when only the first 100 are named. Ask with mode: "dataset" when the answer is a LIST the reader will act on — and always when a rows answer came back truncated. That stores every registration as a dataset the app renders directly and the CSV carries whole, instead of naming the first 100 and leaving the rest to be retyped: Storo Storsenter registers 153, and a capped list is where a table stops matching its own count. The dataset answer is a small envelope — columns, counts, a five-row preview and merknader — and the rows are read from the stored file, never from the preview.

Hands off to get_property_tenancy

Field Type Accepted values
unitkeysrequired≤ 25 items string[]
mode string

rows dataset

maxTimeMS integer

Businesses and premises

get_registered_leases

The tinglyste leieforhold on a property — leases someone paid to register in the grunnbok — with tenants, the nominal yearly rent of the tinglysing year, area and kr/m² where recorded, and the registered text lines.

When to use it For "finnes det tinglyste leiekontrakter her" and for reading what an old registered lease actually said. It takes matrikkelnummer, up to 25 per call, copied out of a next block. It is NOT the rental picture of the property today: most modern leases are never tinglyst, so use it as a record of what was registered, alongside get_property_occupants for who is registered at the address now.

What comes back Standing leases first, then historic, newest tinglysing first. aarlig_leie is the NOMINAL figure of the tinglysing year — a 1963 lease is in 1963-kroner and must never be presented as current rent; the tinglyst year travels beside it for exactly that reason. leie_kilde: "fritekst" means the figure was parsed out of the registered text lines, which are included verbatim in tekster — quote them when precision matters. An empty answer proves nothing about whether the property is let; say "no registered leases", never "no leases". The corpus skews old, with most registrations from the 1980s–90s.

Field Type Accepted values
unitkeysrequired≤ 25 items string[]
maxTimeMS integer

Market statistics

Sold homes and the homes on the market today — as aggregate statistics, or as the individual records behind them. Plus the commercial side of the same question: what næringslokaler ask in rent, and what næring, fritid and tomt ask in price. Every figure in this group is ASKED rather than achieved, and every one carries the coverage it was computed over.

Market statistics

summarize_sold_homes

Aggregate statistics over verified sold homes: counts, averages, kr/m², sold-vs-asking and days on market — by municipality, county or bydel, over a window of up to 12 months.

When to use it For the trend line. For the individual homes behind the numbers — a table, a top-20, links — use search_sold_homes. It narrows on the same row filters as search_sold_homes — build year, price, kr/m², size, rooms, bedrooms, energy label, the features, how far over asking a home went and how long it lay out — so «hvor mange leiligheter bygget etter 2010 gikk over prisantydning» is one aggregate call rather than pages of sales counted by hand. Set agency with groupBy: "agent" to rank meglere within an office, or groupBy: "agency" to rank the offices — in a kommune, a fylke or nationally. Below the kommune the offices are ranked too: groupBy: "agency" with a bydel_navn, a delbydel, grunnkrets or delområde, or a radius — and no agency/agent — answers «hvilke meglerkontorer har solgt flest på Grünerløkka» in one call, counted from the verified sales rather than the agent↔listing index, which is kommune-level. That ranking takes the row filters and carries the price metrics per office; a per-agent ranking cannot follow it, because the register names the office and never the megler. Several periods at once: windows answers up to twelve of them in ONE call, each with its own period and its own row-filter override, so a year-by-year series with a rolling build year is one call rather than eleven — and eleven is most of the tool budget for a single turn. A window that names a period replaces the call-level one; everything else stays as set at call level, which is what makes the windows comparable, and a window that tries to move the geography or the grouping is refused rather than obeyed. The reply carries windows, one figure-bearing line per window in the order asked for, and results, the full envelope for each window at the same indexes.

What comes back Aggregates only — never a raw row or an address. groupBy: "month" is the shape a chart wants; none gives one summary. format: "data" returns the numbers alone; format: "deck", the default, appends a short instruction asking the assistant to render them as a self-contained HTML presentation. data_quality counts, per metric, the provably impossible values excluded from its average, while num_sales still counts every transaction in the bucket. A row filter beside an agency/agent ranking is refused rather than dropped: that leaderboard is counted from the agent↔listing index, which holds no build year, price or size. An office ranking below the kommune is a different population — verified sales, which name the office on 99.5 % of rows — and says so: agency_coverage counts the sales with and without an office, «(ukjent)» is the bucket without one, and the legend states that a sale enters this register when it is registered, so the newest weeks undercount against the ad-counted kommune-level ranking; the two are compared by definition, never by total. A month series carries the figures a reader would otherwise total up by hand: the average per month, the quietest month and the busiest one, each with its month, sit in overall alongside the number of month buckets the average divides by. That divisor is returned because it is the part that surprises — in groupBy "month" a month with no rows produces no bucket and is not in it, while "active_month" returns every month the window touches, zeros included.

↳ markedstall · ↳ ukjent-bydel

Narrowing — needs at least one of lastMonths · from · windows · agency

Field Type Accepted values
municipality_name string
municipality_number string
county_name string
county_number string
bydelsnavn string
grunnkretsnavn string
delomradesnavn string
delbydelsnavn string
property_type string | string[]
ownership_type string | string[]
lat-90–90 number
lng-180–180 number
radius_km number
grunnkrets_name string
delomrade_navn string
delbydel_navn string
dateFielddefault "sold_date" string

sold_date document_date latest_date

lastMonths1–12 integer
from string
to string
min_price number
max_price number
min_sqm_price number
max_sqm_price number
min_sqm number
max_sqm number
min_rooms number
max_rooms number
min_bedrooms number
max_bedrooms number
min_build_year number
max_build_year number
energy_label string
min_over_asking_pct number
min_days integer
max_days integer
has_elevator boolean
has_balcony boolean
has_fireplace boolean
has_parking boolean
beach_front boolean
has_charging boolean
has_sauna boolean
has_roof_terrace boolean
has_rental_unit boolean
kommune_name string
kommune_number string
fylke_name string
fylke_number string
bydel_navn string
housingtype string | string[]
ownershiptype string | string[]
agency string
agent string
groupBydefault "month" string

none month kommune fylke bydel delomrade delbydel grunnkrets housingtype ownershiptype agent agency

windows≤ 12 items object[]
formatdefault "deck" string

deck data

maxTimeMS integer

Market statistics

summarize_homes_for_sale

The same engine pointed at the active for-sale inventory: how much is on the market, at what asking price per m², how long it has been listed.

When to use it The supply-side counterpart to summarize_sold_homes — put the two next to each other to compare what is being asked with what is being paid. It narrows on the same row filters as search_homes_for_sale — build year, price, kr/m², size, rooms, bedrooms, energy label, days on market — so «hvor mange boliger bygget 2021–2026 ligger ute» is one aggregate call rather than pages of listings counted by hand. It offers two month series, and they are not the same curve: groupBy "month" counts the ads ADDED that month among the homes still for sale, so it decays going backwards in time as older ads leave the book, while groupBy "active_month" counts the STOCK — every home that was on the market during the month, the ones since sold or withdrawn included — which is what «lå ute», «har ligget for salg», «var til salgs» and beholdning actually mean. A listing has a third end besides selling and still being out there, and outcome:"withdrawn" is it: the homes TAKEN OFF the market without a sale — «trukket fra markedet», «trukket», «avpublisert», «tatt av markedet», «ikke solgt, fjernet», «inaktive annonser». A sold home is never one of them. That mode answers the count and the share in the same call, because 261 withdrawals in Oslo in June is not a fact anybody can use without knowing 261 out of what. And outcome:"all" is the split — every home on the market in the period, counted by how it left: sold, withdrawn, or still for sale at the end — which is «andel solgt vs trukket» and «hva skjedde med boligene som lå ute i juni». Several periods at once: windows answers up to twelve of them in ONE call, each with its own period and its own row-filter override, so a year-by-year series with a rolling build year is one call rather than eleven — and eleven is most of the tool budget for a single turn. A window that names a period replaces the call-level one; everything else stays as set at call level, which is what makes the windows comparable, and a window that tries to move the geography or the grouping is refused rather than obeyed. The reply carries windows, one figure-bearing line per window in the order asked for, and results, the full envelope for each window at the same indexes.

What comes back Resale homes (bruktbolig) only; new-builds are not in the corpus. The AVM estimate and the asking-vs-estimate ratio are part of a separate add-on — see what a key reaches, below. A row filter beside an agency/agent ranking is refused rather than dropped: that leaderboard is counted from the agent↔listing index, which holds no build year, price or size. The stock series returns num_listings alone, covers whole calendar months, defaults to the last twelve, and counts homes first advertised up to 24 months before the window; its monthly figures overlap — a home on the market from March to June is in all four — so they are never summed, and the overall figure counts each home once. It takes no agency/agent ranking and no days-on-market bound, because neither can say anything about a past month. A month series carries the figures a reader would otherwise total up by hand: the average per month, the quietest month and the busiest one, each with its month, sit in overall alongside the number of month buckets the average divides by. That divisor is returned because it is the part that surprises — in groupBy "month" a month with no rows produces no bucket and is not in it, while "active_month" returns every month the window touches, zeros included. A withdrawal answer carries three figures per bucket rather than one — how many were pulled, the stock they were pulled out of, and the share those two make — and the stock behind that share is clipped to the period rather than rounded out to whole calendar months, so a period starting mid-month never divides a few days of withdrawals by a whole month of inventory. Its one approximation is the same 24-month look-back the stock series carries: a home first advertised longer ago than that and withdrawn inside the period is counted as withdrawn but is not in the denominator, which on the live book is around one withdrawal in a hundred. The count stays exact, because the count is the answer. The split is a counting mode — counts and shares of the stock, no price metrics — and every figure in a bucket is read off the same homes in one pass, so the three counts sum to the stock and the three shares to one. Its withdrawn count is taken inside that look-back rather than off the withdrawn index, so it can differ from outcome "withdrawn" by a handful for the same period; the legend says so and in which directions. It carries none of the month figures — three overlapping stocks have no one figure to average — and every answer carries the definitions in one line each: SOLD = the broker marked the ad sold (sold: true) — the brokered sale, weeks before it is tinglyst; counted when the home left the market, normally sold_date. WITHDRAWN = taken off the market with no sale recorded (inactive: true, sold null), dated by inactive_date. STILL ON MARKET = on the market in the period and neither sold nor withdrawn by the end of it.

↳ trukket-fra-markedet

Field Type Accepted values
kommune_name string
kommune_number string
fylke_name string
fylke_number string
bydel_navn string
grunnkrets_name string
delomrade_navn string
delbydel_navn string
housingtype string | string[]
ownershiptype string | string[]
lat-90–90 number
lng-180–180 number
radius_km number
grunnkretsnavn string
delomradesnavn string
delbydelsnavn string
lastMonths1–12 integer
from string
to string
min_price number
max_price number
min_sqm_price number
max_sqm_price number
min_sqm number
max_sqm number
min_rooms number
max_rooms number
min_bedrooms number
max_bedrooms number
min_build_year number
max_build_year number
energy_label string
min_days integer
max_days integer
county_name string
county_number string
municipality_name string
municipality_number string
bydelsnavn string
property_type string | string[]
ownership_type string | string[]
agency string
agent string
outcomedefault "active" string

active withdrawn all

groupBydefault "month" string

none month active_month county municipality bydel delomrade delbydel grunnkrets property_type ownership_type agent agency

windows≤ 12 items object[]
formatdefault "deck" string

deck data

maxTimeMS integer

Market statistics

search_sold_homes

The individual sold records behind the statistics — one row per home, each with its new_unitkey, a Finn URL, a Solgt URL, sold and asking price, area and dates.

When to use it For tables, top-N lists and drill-downs. A sold_date window is required and may not exceed 12 months; a page holds 25 rows by default and 1000 at most, and each row counts against the document quota. A street is a geography of its own: street with a kommune answers «hva er solgt i Thereses gate det siste året» with the homes whose registered address is on that street — every house number, matched against the register's own address string with the usual abbreviations resolved — and never with a radius around one of them. It takes the street NAME; a house number on it is refused and the name to send is given back, because one address is resolve_property's question.

What comes back Sortable on computed fields — over_asking_pct and days_on_market — so "the 20 homes that went furthest over asking" is one call, not a client-side sort of everything. A street-scoped answer carries a street block naming the street, the spellings it matched and the kommune, and an empty one says whether the street exists at all: not_found on street means no home was ever listed under that name in the kommune, while empty means the street is real and the window quiet. mode:"dataset" answers the whole result set at once: the rows are stored as a file the calling application renders itself and the call returns a small envelope — columns, row count, a five-row preview and the caveats — so a list longer than a page never has to be paged, and never passes through the model that would retype it.

Narrowing — needs at least one of lastMonths · from

Field Type Accepted values
municipality_name string
municipality_number string
county_name string
county_number string
bydelsnavn string
grunnkretsnavn string
delomradesnavn string
delbydelsnavn string
property_type string | string[]
ownership_type string | string[]
lat-90–90 number
lng-180–180 number
radius_km number
grunnkrets_name string
delomrade_navn string
delbydel_navn string
lastMonths1–12 integer
from string
to string
kommune_name string
kommune_number string
fylke_name string
fylke_number string
bydel_navn string
street string
housingtype string | string[]
ownershiptype string | string[]
agency string
agent string
min_price number
max_price number
min_sqm_price number
max_sqm_price number
min_sqm number
max_sqm number
min_rooms number
max_rooms number
min_bedrooms number
max_bedrooms number
min_build_year number
max_build_year number
energy_label string
min_over_asking_pct number
min_days integer
max_days integer
has_elevator boolean
has_balcony boolean
has_fireplace boolean
has_parking boolean
beach_front boolean
has_charging boolean
has_sauna boolean
has_roof_terrace boolean
has_rental_unit boolean
mode string

rows dataset

sort_bydefault "sold_date" string

sold_date sold_price sqm_price over_asking_pct days_on_market build_year

sort_dirdefault "desc" string

asc desc

page≥ 0default 0 integer
pageSize integer
maxTimeMS integer

Market statistics

search_homes_for_sale

The individual active listings: asking price, total price including omkostninger, days on market, area and agency, each with a Finn and a Solgt URL.

When to use it A narrowing filter is required — geography, a date window, or a price/size bound — because the inventory is not a browsable catalogue. A page holds 25 rows by default and 1000 at most. street with a municipality lists the homes for sale on one street — the register's own address string, every house number, never a radius — and takes the street NAME alone. outcome:"withdrawn" points the same rows at the homes that were TAKEN OFF the market without a sale, which is the drill-down behind a withdrawal count.

What comes back mode:"dataset" answers the whole result set at once: the rows are stored as a file the calling application renders itself and the call returns a small envelope — columns, row count, a five-row preview and the caveats. Ask for it instead of paging. A COUNT is a different question and belongs in summarize_homes_for_sale, which takes the same row filters. A withdrawn row carries withdrawn_date, and its days_on_market is the time it actually lay out — listed until pulled, not until today — so min_days/max_days and sorting by it select on exactly that. An agency/agent filter is refused in that mode rather than dropped: the agent↔listing index behind it records who is selling what today and holds no withdrawn ad.

About — needs at least one of county_name · county_number · municipality_name · municipality_number · bydelsnavn · grunnkretsnavn · delomradesnavn · delbydelsnavn · fylke_name · fylke_number · kommune_name · kommune_number · bydel_navn · grunnkrets_name · delomrade_navn · delbydel_navn · lat + lng + radius_km

Narrowing — needs at least one of lastMonths · from · agency · agent · min_price · max_price · min_sqm_price · max_sqm_price · min_sqm · max_sqm · min_rooms · max_rooms · min_bedrooms · max_bedrooms

Field Type Accepted values
kommune_name string
kommune_number string
fylke_name string
fylke_number string
bydel_navn string
grunnkrets_name string
delomrade_navn string
delbydel_navn string
housingtype string | string[]
ownershiptype string | string[]
lat-90–90 number
lng-180–180 number
radius_km number
grunnkretsnavn string
delomradesnavn string
delbydelsnavn string
lastMonths1–12 integer
from string
to string
outcomedefault "active" string

active withdrawn

county_name string
county_number string
municipality_name string
municipality_number string
bydelsnavn string
street string
property_type string | string[]
ownership_type string | string[]
agency string
agent string
min_price number
max_price number
min_sqm_price number
max_sqm_price number
min_sqm number
max_sqm number
min_rooms number
max_rooms number
min_bedrooms number
max_bedrooms number
min_build_year number
max_build_year number
energy_label string
min_days integer
max_days integer
has_balcony boolean
has_elevator boolean
has_fireplace boolean
has_parking boolean
beach_front boolean
has_charging boolean
has_sauna boolean
has_roof_terrace boolean
has_rental_unit boolean
min_asking_vs_estimate number
max_asking_vs_estimate number
min_price_changes integer
mode string

rows dataset

sort_bydefault "added_date" string

added_date list_price sqm_price asking_vs_estimate days_on_market build_year

sort_dirdefault "desc" string

asc desc

page≥ 0default 0 integer
pageSize integer
maxTimeMS integer

Market statistics

get_homes_by_unitkey

Drill-down by new_unitkey: for up to 25 keys, the latest sold record and the active for-sale record for each, merged into one entry per key.

When to use it new_unitkey is the stable id that leads every row from the search tools, so this is how you fetch full detail for the homes an earlier search surfaced.

Field Type Accepted values
unitkeysrequired≤ 25 items string[]
maxTimeMS integer

Market statistics

get_commercial_rent_stats

Median, p25 and p75 asking rent for næringslokaler in kr/m²/år, over a geography you name — the first tool on this surface that answers with a derived number rather than with rows. It returns no properties and no listings.

When to use it For "hva er leieprisen for kontor i Oslo", "hva koster lager i Fredrikstad" and "har leieprisene steget siden 2020". search_commercial_properties answers with the PROPERTIES a business operates from and search_homes_for_sale with bolig listings; this one answers with the market's numbers. A geographic scope is required — kommune, fylke or postnummer — because a national median over this corpus would mix Oslo kontor with kerbside parking in Finnmark and read as a market it does not describe. property_type is membership rather than equality, since an advert carries several kinds of use at once, and the values are single tokens: "Butikk/Handel" is ONE of them, so splitting it on the slash matches nothing at all. mode:"count" returns the statistics with group_by over year, kommune or property type; mode:"rows" returns the priced adverts behind them so a median can be checked against the ads it came from; mode:"dataset" runs the whole scope and stores it as a file the calling application renders. Several periods at once: windows answers up to twelve of them in ONE call, in mode:"count" only, each with its own years and its own property_type, so a year-by-year comparison is one call rather than a dozen. The geography stays as set at call level, which is what makes the windows comparable; compare_with and windows are refused together, because each multiplies the queries and together they multiply each other.

What comes back unit is on every response and must be read off it rather than assumed — it is the one field that decides whether the answer is right. Bolig-leie is quoted in kr/MÅNED and næringsleie in kr/m²/ÅR, the same underlying field name roughly twelvefold apart. The source itself carries two units under that one name: some meglere enter a total årsleie and others enter kr/m²/år, and the answer states how many rows had to be divided by their area to reach a common scale. Every figure is ASKING rent and never contracted rent — what a tenant actually signed is in no register we hold, and the gap between the two is real. Read coverage before describing any median: only about 5.7 % of kontor adverts carry a price at all, so the number is a fact about the priced fraction and never a description of the whole market, and the block states how many adverts sit on the other side of that. A group with fewer than 15 priced adverts keeps its median and gains tynt_grunnlag: true — report it WITH its n and the flag rather than presenting it as solid or withholding it, because the thin number is still the only one the corpus holds. What must never happen is fixing a thin sample by dropping the type filter: pooling kinds of premises multiplies the sample and produces a figure that describes no market anyone can rent in. Measured over Oslo, Butikk/Handel runs at 2 375 kr/m²/år and Lager/Logistikk at 1 100 — 2.2× apart — and all types pooled gives 1 500 over 884 adverts, which is right for neither. The supported move is the opposite one, and compare_with is the only widening the tool offers: it moves the GEOGRAPHY while holding the property type and the year range fixed, returns the requested scope completely unchanged, and adds the wider figure as a separate block carrying its own note saying it is different geography. Ås kontor stays at n=7 with Nordre Follo kontor beside it, and the wider block must never be presented as the answer to the narrower question. rows_excluded_sanity counts adverts whose stated price was impossible, such as the one stating 12 001 500 kroner on 30 m²; they are dropped from the median and counted in the open, because a filter nobody is told about is a lie. Geography resolves through the postal-code table, so a postnummer straddling a kommune boundary follows that table's assignment.

About — needs at least one of kommune · fylke · postnummer

Field Type Accepted values
kommune≤ 30 items string[]
fylke string
postnummer≤ 400 items string[]
from_year1990–2100 integer
to_year1990–2100 integer
property_type string[]

Kontor Lager/Logistikk Kombinasjonslokaler Butikk/Handel Garasje/Parkering Produksjon/Industri Andre Verksted Undervisning/Arrangement Serveringslokale/Kantine Kjøpesenter Bygård/Flermannsbolig Næringstomt Prosjekt Hotell/Overnatting Gårdsbruk/Småbruk Tomter Leilighet

group_by string

year kommune property_type

compare_with≤ 30 items string[]
mode string

count rows dataset

limit≤ 200 integer
windows≤ 12 items object[]
maxTimeMS integer

Market statistics

get_commercial_sale_stats

Median, p25 and p75 PRISANTYDNING for commercial premises, holiday property and bare land — in kroner, or per square metre with the area basis named. The sale-side twin of get_commercial_rent_stats, over the same engine.

When to use it For "hva koster næringslokaler i Oslo", "kvadratmeterpris for kontor i Bergen", "hyttepriser i Trysil" and "tomtepriser i Ås". It is NOT a record of what anything sold for: search_sold_homes and get_comparable_sales carry ACHIEVED prices from the register, and these are ADVERTISED asking prices, which is a different number and must never be presented as the other. vertical picks one of three separate corpora — business_sales, leisure_sale or plots — deliberately not pooled, because their per-m² figures are not comparable: a hytte's floor metre and a tomt's land metre differ by more than an order of magnitude, so an average across them describes nothing. A geographic scope is required, and property_type is validated against the CHOSEN vertical's own vocabulary, so a type that corpus does not use is refused by name instead of returning a confident zero. Several periods at once: windows answers up to twelve of them in ONE call, in mode:"count" only, each with its own years and its own property_type, so a year-by-year comparison is one call rather than a dozen. The geography stays as set at call level, which is what makes the windows comparable; compare_with and windows are refused together, because each multiplies the queries and together they multiply each other.

What comes back unit names the area basis, and that is the point of it: kr is the asking price, kr/m2_gulv divides by FLOOR area and kr/m2_tomt by PLOT area. Both of the latter are "kr/m²" in ordinary speech, which is exactly why the response spells out which one it is — a tomt at 1 500 kr/m² is ordinary and a floor at 1 500 kr/m² is a data-entry error. The plots corpus records no floor area at all, so it always uses the plot and refuses a floor basis rather than answering emptily. These corpora are far better priced than the rental one — about 81 % of commercial sale adverts and 99 % of leisure adverts carry a price — but coverage still decides how a number may be described, and rows_excluded_no_area is what matters for a per-m² answer, because roughly a third of commercial sale adverts state no area at all and drop out of it entirely. A group under 15 priced adverts keeps its median and gains tynt_grunnlag: true, and the way to strengthen it is compare_with — a wider GEOGRAPHY with the vertical, type, metric and years all held fixed, added as a labelled block beside the requested scope rather than replacing it. Never grow the sample by pooling property types or by switching vertical: that buys a bigger number describing none of the things it was averaged over. rows_excluded_sanity counts impossible figures dropped from the median: the bottom of every one of these verticals contains placeholder prices of a single krone.

About — needs at least one of kommune · fylke · postnummer

Field Type Accepted values
vertical string

business_sales leisure_sale plots

kommune≤ 30 items string[]
fylke string
postnummer≤ 400 items string[]
metric string

pris kvadratmeterpris

area_basis string

gulv tomt

from_year1990–2100 integer
to_year1990–2100 integer
property_type string[]
group_by string

year kommune property_type

compare_with≤ 30 items string[]
mode string

count rows dataset

limit≤ 200 integer
windows≤ 12 items object[]
maxTimeMS integer

Market statistics

get_residential_rent_stats

Median, quartiles and kr/m² per month of ASKING RENT for homes, from rental adverts, over a kommune, a bydel, a fylke or a set of postal codes — with the number of ads behind every figure.

When to use it For «hva er realistisk leie for en 2-roms på Grünerløkka», «hva koster det å leie enebolig i Bærum», «har leieprisene i Bergen steget» and «hva kan jeg ta i leie». It is the residential twin of get_commercial_rent_stats and answers in kr per MONTH where that one answers in kr/m² per YEAR; unit is on every response so the two are never confused. The corpus records SOVEROM, not rooms: a «1-roms» is a studio with 0 bedrooms on most ads and 1 on some, so it is asked as max_bedrooms: 1 with a size band, and a «2-roms» is one bedroom. A geographic scope is required; a bydel resolves to the postal codes whose verified sales mostly lie in it, and the codes that straddle a border are named. The window is the advert's publication date, twelve months by default and two years at most. Without a property_type the answer covers whole dwellings and hybler and says so; a room in a shared flat, a garage or a cabin is counted only when named. mode:"rows" returns the adverts behind the numbers, newest first, and mode:"dataset" stores the whole set as a file.

What comes back Asking rent, never contracted rent, and the caveats say so in Norwegian on every answer. overall and each group carry n, the n the median actually rests on, median, p25/p75, p10/p90, mean, min, max and a kr_per_m2_mnd block with its own n — the ads that also state an area (P-rom, else BRA-i). coverage separates the ads in scope from the ones priced, the placeholder prices dropped (the corpus holds ads asking 1 kr) and the share with an area. A group under fifteen ads keeps its figures and gains tynt_grunnlag: true; the honest repair is a wider geography or window with the type and bedrooms held fixed, never a pooled sample. Percentiles are computed in the database (t-digest), measured against the exact interpolation to within a rounding step.

About — needs at least one of kommune · fylke · postnummer

Field Type Accepted values
kommune≤ 30 items string[]
bydel string
fylke string
postnummer≤ 400 items string[]
lastMonths1–24 integer
from string
to string
property_type string[]

Leilighet Enebolig Rekkehus Tomannsbolig Hybel Rom i bofellesskap Hytte Garasje/Parkering Andre Annet fritid Bygård/Flermannsbolig Gårdsbruk/Småbruk Kontor Lager/Logistikk Butikk/Handel Produksjon/Industri Næringstomt Tomter

min_bedrooms≥ 0 integer
max_bedrooms≥ 0 integer
min_sqm number
max_sqm number
group_by string

bedrooms property_type kommune month

mode string

count rows dataset

limit≤ 200 integer
maxTimeMS integer

Market statistics

get_listing_full

One Finn ad, whole: the seller's presentation as it ran — title, prices with omkostninger, key facts, every image with its megler caption, viewings, price history, and the ad's own matrikkel keys for checking the claims against the registers.

When to use it For "hva sto i annonsen" and everything the ad itself can answer — including "finnes det bilder av badet", which the image captions answer. It takes a finnkode from a search row or a finn.no URL, and all five verticals answer (homes, lettings, business_sales, leisure_sale, new_buildings); the payload names which one held the ad. The prose is windowed by section — every heading is always listed, contents eight sections per call, next carries the rest — so read on before claiming the ad is silent on something.

What comes back The ad is MARKETING: the selling side's presentation, megler captions included. Present its claims as the listing's claims — the registered facts live in get_property_facts, get_owners and get_conveyances, and matrikkel hands over the full five-segment keys to check with. When an archived salgsoppgave exists for the ad, next.get_salgsoppgave says so; sold/inactive status and dates come from the archive row, not the ad text.

Hands off to get_salgsoppgave

Field Type Accepted values
finnkoderequired integer
text_offset≥ 0 integer
include_images boolean
maxTimeMS integer

Market statistics

get_salgsoppgave

The listing's own documents read as text — the salgsoppgave with the takstmann's tilstandsrapport and the verditakst inside it, which is where the TG-graderinger live — plus TG2/TG3/TGIU counts and the takstmann's kostnadsanslag in kroner, both parsed from that text.

When to use it For "les salgsoppgaven" and every TG question: TG2/TG3 findings, «hva må utbedres», what the tilstandsrapport says about a specific room, the estimated cost bands. It is also where a TAKST is answered from — «hva er taksten», «verditakst», «hva satte takstmannen» ask for the takstmann's own signed figure for that home, which is in this document; Solgt.no's model estimate over comparable sales is the other question, and that one is get_avm. It takes a finnkode. A full prospekt runs to 50+ pages, so the text arrives windowed — offset/length, 20 000 characters by default, with next carrying the following window. Coverage is partial: ~190 000 archived prospekter against 1.76 million ads, so an empty answer is a statement about our archive, never that no salgsoppgave existed.

What comes back The SELLER'S document, not a register — megler marketing plus the report the selling side paid for. Present its claims as the prospekt's claims and check the facts against get_property_facts, get_owners and get_conveyances. summary carries the TG2/TG3/TGIU counts parsed from the text by a parser scored against hand-counted prospekter — exact or null, never a guess: a null summary means the format could not be read, not that the home has zero findings. method says how it was read: index counted the report's own index and carries the component list, while count_block and stated_count read a tally the report printed for itself and carry no components at all — so an empty component list beside non-zero counts is the whole answer rather than a truncated one. summary.costs is the takstmann's own kostnadsanslag from the same text, in kroner — a band per finding it could attribute and their sum. It is the takstrapport's estimate, not ours, and it is usually incomplete: NS3600 only requires a price on TG3, so partial: true is the norm and the total then covers priced_findings of total_findings, never the whole repair bill. tilstandsgrader is the tilstandsrapport's per-finding grid — one row per finding with the bygningsdel, the takstmann's own wording and his cost band where he priced it — which a client that shows the findings renders from the payload. The wording per row is the takstmann's; the grade a row sits under and the per-grade counts measured unreliable, so the totals come from summary and the rows from tilstandsgrader. archived_at dates the capture — the archive is a point-in-time copy, so the text, summary and tilstandsgrader all describe the edition archived that day rather than whatever the meglerhus serves now (measured: 1 of 20 sampled prospekter had been revised since). pdf_available states whether the archive holds the PDF. It is an existence claim, not a link — the meglerhus's own address is deliberately not carried, because a quarter of those links are dead and a live one returns the same document the archive already holds.

Reached from get_listing_full

Field Type Accepted values
finnkoderequired integer
offset≥ 0 integer
length≤ 40000 integer
maxTimeMS integer

What it is worth

The Solgt.no valuation model, asked directly: the estimate for one home, the sales it finds most comparable, and its price index over time. The whole group is an add-on enabled per key.

What it is worth

get_avmadd-on

The Solgt.no valuation of one home: a point estimate in kroner with a low–high confidence band and kr/m², time-adjusted to today, next to the registered facts the model was given — size, build year, floor, standard scores.

When to use it For «hva er boligen verdt», «verdiestimat», «verdivurdering» and «markedsverdi» about one known unit. It takes unitkey straight out of resolve_property.next.get_avm. A takst is a different question and a different tool: «hva er taksten», «verditakst» and «hva satte takstmannen» ask for the takstmann's own signed figure for that home, which stands in the listing's documents — get_salgsoppgave — and never here. It is a statistical estimate, not a takst: present it with its interval, and read estimate_quality.missing_fields first — an estimate over a missing living area carries that gap in the open rather than hiding it. For the oppussings-what-if — «sett bad og kjøkken til 8» — add standard: { kitchen: 1–10, bathroom: 1–10 }: the model re-runs as if those rooms held that standard. The what-if answer carries its own caveat (a rough estimate at changed standard, never a valuation), echoes the applied scores in standard_override, and belongs BESIDE the baseline call, not instead of it.

What comes back estimate holds the point value, the band, kr/m² and the not-time-adjusted figure from the same model run. unit is what the model was told, so a reader can judge the estimate against the facts behind it. status: partial with a failed estimate section means the model could not be reached — an unknown, never a zero — and not_found means the unit has no valuation base data at all.

Reached from resolve_property

Field Type Accepted values
unitkeyrequired string
standard object

kitchen bathroom

maxTimeMS integer

What it is worth

get_comparable_salesadd-on

The verified sales the valuation model itself scores as most comparable to one home — each with address, sold date and price from the tinglyste omsetning, kr/m², the sale re-priced to today, what that sale implies the subject is worth, and a 0–100 similarity score.

When to use it For «hva har lignende boliger gått for» and «hva solgte naboen for», with the subject's unitkey from resolve_property.next.get_comparable_sales. strategy picks the model's list — balanced by default, or nearest, most recent, same street, or matched on standard. Sold homes by geography and date window, without a subject to compare against, is search_sold_homes; the subject's own sale history is get_conveyances and is deliberately excluded here.

What comes back Sold price and date are public record. indexed_price_nok is that price adjusted for the market's movement since — «prisjustert til i dag», never a valuation of the comp. implied_subject_price_nok is what each sale alone suggests the subject is worth, and the summary's average of it is a cross-check against get_avm, not a second estimate. Comparability is judged on living area, building, build year, distance, floor, housing type, sale year and street.

Reached from resolve_property

Field Type Accepted values
unitkeyrequired string
strategydefault "balanced" string

balanced distance recent same_street high_standard mid_standard low_standard

limit1–20default 10 integer
maxTimeMS integer

What it is worth

get_price_indexadd-on

The Solgt.no price index for one home over a chosen window — quarterly, rebased to 100 at the window start so 118.4 reads directly as +18,4 % — with the property's own registered sales overlaid and adjusted to today's price level.

When to use it For «hvordan har prisene utviklet seg her» and «hva tilsvarer kjøpesummen i dag», with unitkey from resolve_property.next.get_price_index and years for the window. A unit without a series of its own answers from its fylke, and level says which happened — at fylke level the curve describes the county, not the home. Observed market movement over an area, without a model, is summarize_sold_homes across windows.

What comes back trend.series is the rebased quarterly curve and trend.change_pct its whole-window change. sales[] are the property's own priced transfers, each with indexed_to_today_nok — the old price carried forward by the index, which is a price adjustment and not a valuation; the valuation is get_avm. Transfers registered without a price (gift, inheritance) are listed separately as events, not price points.

Reached from resolve_property

Field Type Accepted values
unitkeyrequired string
years1–30default 5 integer
maxTimeMS integer

Vocabulary

What to call things before you build a query.

Vocabulary

describe_dataset

The data dictionary for the market datasets: the aggregate-vs-raw split, the exact values you can filter on, what each metric means, and worked examples in Norwegian.

When to use it Guidance text only — it never touches the database and never returns a schema. Cheap to call first when a filter value is in doubt. Every stored dataset, whichever tool wrote it, carries two lists in its envelope and manifest: merknader, the reader's caveats in Norwegian, which the app renders under the table and into the CSV; and notes, the tool's brief to the model, which is never shown to a reader.

Vocabulary

list_agencies

The canonical agency and brand names you can filter or rank by, with each brand's ad_count and office_count.

When to use it Call it before passing agency to a summarize_* or search_* tool, so the value matches. A name that is not listed still works — it falls back to a name search.

Field Type Accepted values
name string
limit1–200default 40 integer

Retired names

Still registered so existing configurations keep working. Same behaviour, same arguments — use the current name in anything new.

Retired names

generate_transactions_dataretired name

Retired name for summarize_sold_homes. Identical behaviour and arguments.

Narrowing — needs at least one of lastMonths · from · windows · agency

Field Type Accepted values
municipality_name string
municipality_number string
county_name string
county_number string
bydelsnavn string
grunnkretsnavn string
delomradesnavn string
delbydelsnavn string
property_type string | string[]
ownership_type string | string[]
lat-90–90 number
lng-180–180 number
radius_km number
grunnkrets_name string
delomrade_navn string
delbydel_navn string
dateFielddefault "sold_date" string

sold_date document_date latest_date

lastMonths1–12 integer
from string
to string
min_price number
max_price number
min_sqm_price number
max_sqm_price number
min_sqm number
max_sqm number
min_rooms number
max_rooms number
min_bedrooms number
max_bedrooms number
min_build_year number
max_build_year number
energy_label string
min_over_asking_pct number
min_days integer
max_days integer
has_elevator boolean
has_balcony boolean
has_fireplace boolean
has_parking boolean
beach_front boolean
has_charging boolean
has_sauna boolean
has_roof_terrace boolean
has_rental_unit boolean
kommune_name string
kommune_number string
fylke_name string
fylke_number string
bydel_navn string
housingtype string | string[]
ownershiptype string | string[]
agency string
agent string
groupBydefault "month" string

none month kommune fylke bydel delomrade delbydel grunnkrets housingtype ownershiptype agent agency

windows≤ 12 items object[]
formatdefault "deck" string

deck data

maxTimeMS integer

Retired names

generate_listings_dataretired name

Retired name for summarize_homes_for_sale. Identical behaviour and arguments.

Field Type Accepted values
kommune_name string
kommune_number string
fylke_name string
fylke_number string
bydel_navn string
grunnkrets_name string
delomrade_navn string
delbydel_navn string
housingtype string | string[]
ownershiptype string | string[]
lat-90–90 number
lng-180–180 number
radius_km number
grunnkretsnavn string
delomradesnavn string
delbydelsnavn string
lastMonths1–12 integer
from string
to string
min_price number
max_price number
min_sqm_price number
max_sqm_price number
min_sqm number
max_sqm number
min_rooms number
max_rooms number
min_bedrooms number
max_bedrooms number
min_build_year number
max_build_year number
energy_label string
min_days integer
max_days integer
county_name string
county_number string
municipality_name string
municipality_number string
bydelsnavn string
property_type string | string[]
ownership_type string | string[]
agency string
agent string
outcomedefault "active" string

active withdrawn all

groupBydefault "month" string

none month active_month county municipality bydel delomrade delbydel grunnkrets property_type ownership_type agent agency

windows≤ 12 items object[]
formatdefault "deck" string

deck data

maxTimeMS integer

Worked examples

Every request below was run against the live server, and every response is that server's own, trimmed with where a list repeats itself.

From an address to the owners

One address, one building, twenty-one registered properties. The second call takes next.get_owners from the first, exactly as it came.

  1. resolve_property

    {
      "name": "resolve_property",
      "arguments": {
        "address": "Akersgata 32",
        "kommune": "Oslo"
      }
    }
    Resolved 21 of 21 requested properties via address (index `bruksenheter.adresse_1 + bruksenhet.adresse_1`).
    "Akersgata 32" in kommune 0301 → 21 of 21 unit(s) at entrance Akersgata 32. These units ARE the answer (level: mixed).
    
    {
      "status": "ok",
      "shown": 21,
      "total": 21,
      "next": {
        "get_conveyances": {
          "unitkeys": ["0301-208-1-0-0", "0301-208-1-0-1", … , "0301-208-1-0-20"]
        },
        "get_owners": {
          "unitkeys": ["0301-208-1-0-0", "0301-208-1-0-1", … , "0301-208-1-0-20"]
        }
      },
      "budget": { "db_ms": 24, "hops": 2, "rows_cap": 25 }
    }
  2. get_owners

    next.get_owners, passed through unchanged.

    {
      "name": "get_owners",
      "arguments": {
        "unitkeys": ["0301-208-1-0-0", "0301-208-1-0-1", "0301-208-1-0-2", "0301-208-1-0-3", "0301-208-1-0-4", "0301-208-1-0-5", "0301-208-1-0-6", "0301-208-1-0-7", "0301-208-1-0-8", "0301-208-1-0-9", "0301-208-1-0-10", "0301-208-1-0-11", "0301-208-1-0-12", "0301-208-1-0-13", "0301-208-1-0-14", "0301-208-1-0-15", "0301-208-1-0-16", "0301-208-1-0-17", "0301-208-1-0-18", "0301-208-1-0-19", "0301-208-1-0-20"]
      }
    }
    20 registered owner(s) across 21 of 21 requested properties.
    A private individual's number is masked (DDMMYYXXXXX); a company's organisasjonsnummer is public and shown in full. `owners_read_from` names the document each answer came off — for a seksjon that is the parcel, whose OWN owner is somebody else.
    
    {
      "status": "ok",
      "shown": 20,
      "total": 21,
      "notes": [
        "0301-208-1-0-0 is a sameie matrikkelenhet with 20 sub-units and NO owner of its own — it is owned one level down, seksjon by seksjon. …"
      ],
      "properties": [
        {
          "requested": "0301-208-1-0-0",
          "level": "parcel",
          "type": "Matrikkelenhet",
          "address": "Akersgata 32, 0180 OSLO",
          "owners_status": "owned_at_unit_level",
          "owners": [],
          "owned_units": { "antall": 20, "unitkeys": ["0301-208-1-0-1", … ] }
        },
        {
          "requested": "0301-208-1-0-4",
          "level": "unit",
          "type": "Seksjon",
          "owners_status": "ok",
          "owners_read_from": { "new_unitkey": "0301-208-1-0-0", "property_type": "sameie" },
          "owners": [
            {
              "navn": "AKERGREN AS",
              "safe_number": "982022568",
              "type": "JuridiskPerson",
              "ownership": { "prosent": 100, "type": "Eiendomsrett" },
              "grunnbok_id": 8244529
            }
          ]
        }
        … 19 more seksjoner, held by AKERGREN AS and GRENSEN 15 AS …
      ]
    }

The point The matrikkelenhet itself has no owner, and that is not a gap: a sameie is owned seksjon by seksjon, and the answer says so rather than returning nothing. Twenty-one properties, twenty owners, and the one property without one is the building, not a hole in the register.

From a seksjon to the municipal cases

next.get_innsyn_cases comes back with two keys where the other hops have one: the seksjon's and the matrikkelenhet's. That is not duplication — the municipality files against the parcel, and passing next through unchanged is how you ask at the right level without having to know that.

  1. resolve_property

    {
      "name": "resolve_property",
      "arguments": {
        "new_unitkey": "0301-208-1-0-4"
      }
    }
    Resolved 1 of 1 requested property via unitkey (index `new_unitkey_1`).
    
    {
      "status": "ok",
      "shown": 1,
      "total": 1,
      "next": {
        "get_conveyances": { "unitkeys": ["0301-208-1-0-4"] },
        "get_owners":      { "unitkeys": ["0301-208-1-0-4"] },
        "get_innsyn_cases": {
          "unitkeys": ["0301-208-1-0-4", "0301-208-1-0-0"],
          "level": "unit"
        },
        "get_encumbrances": { "registerenhet_ids": [4112100], "level": "unit" }
      },
      "budget": { "db_ms": 23, "hops": 1, "rows_cap": 5 }
    }
  2. get_innsyn_cases

    Two keys, because next said two. level: "unit" does not filter anything — it decides how a case found on the parcel must be described.

    {
      "name": "get_innsyn_cases",
      "arguments": {
        "unitkeys": ["0301-208-1-0-4", "0301-208-1-0-0"],
        "level": "unit",
        "limit": 3
      }
    }
    32 sak(er) on this property; showing 3 row(s).
    Case types in `type_breakdown` and on each row are INFERRED FROM THE TITLE — Innsyn records none. …
    Kommune coverage: oslo (Innsyn holds 61 of Norway's kommuner, and 4.0 % of the cases it holds are unreachable by any property lookup).
    
    {
      "status": "ok",
      "shown": 3,
      "total": 32,
      "span": { "total": 32, "earliest_saksaar": 1884, "latest_saksaar": 2022 },
      "counts": { "linked": 32, "on_parcel": 32, "on_unit": 0, "cases_on_page": 3, "set_aside": [] },
      "type_breakdown": [ … 18 ukjent, 11 byggesak, 1 administrativt, 1 tilsyn og ulovlighet, 1 deling og oppmåling … ],
      "cases": [
        {
          "saksnummer": "2022/10223",
          "saksaar": 2022,
          "tittel": "Akersgata 32 - Sikkerhetskontroll - Løpenummer: 16222",
          "publisert": "2022-07-11",
          "case_type": { "id": "administrativt", "label": "Administrativt", "basis": "sikkerhetskontroll" },
          "registered_on": "parcel",
          "matched_unitkey": "0301-208-1-0-0",
          "properties_on_case": 1,
          "documents": { "state": "listed_only", "total": 1, "in_app": 0, "drawings": 0, "shown": [ … ] }
        },
        {
          "saksaar": 2018,
          "tittel": "Akersgata 32 - Etablering av interntrapp mellom 6 og 7 etasje",
          "case_type": null,
          "registered_on": "parcel"
        },
        {
          "saksaar": 2017,
          "tittel": "Akersgata 32 - Oppføring av bysykkelstativ - 04-320",
          "case_type": { "id": "byggesak", "label": "Byggesak", "basis": "oppføring" },
          "registered_on": "parcel"
        }
      ]
    }

The point on_parcel: 32, on_unit: 0 — every single case sits on the matrikkelenhet, none on the seksjon. Read registered_on before you describe a case: these concern the building, not this particular apartment. And case_type: null on the middle row is not a missing category; it is a title the vocabulary did not recognise, which is often ordinary building work.

From a seksjon to the building it stands in

The key names one apartment; the answer describes the whole block, and it says so on the row rather than in a footnote. Buildings are recorded on the matrikkelenhet, so this tool climbs to it for you — which is exactly why the numbers below are the property's and not the flat's.

  1. get_property_facts

    The seksjon key, straight out of resolve_property.next.get_property_facts. Nothing had to be resolved to the parcel first.

    {
      "name": "get_property_facts",
      "arguments": {
        "unitkeys": ["0301-208-1-0-4"]
      }
    }
    2 building(s) across 1 of 1 requested property.
    BYGNINGER, UTLEIE OG PARKERING ER REGISTRERT PÅ MATRIKKELENHETEN, ikke på den enkelte seksjonen eller borettslagsandelen. …
    
    {
      "status": "ok",
      "shown": 1,
      "total": 1,
      "next": {
        "get_owners":      { "unitkeys": ["0301-208-1-0-0"] },
        "get_conveyances": { "unitkeys": ["0301-208-1-0-0"] }
      },
      "budget": { "db_ms": 47, "hops": 2, "rows_cap": 50 },
      "sections": {
        "eiendom":          { "status": "ok", "data": { "matched": 1 }, "ms": 25 },
        "borettslagsandel": { "status": "skipped", "data": null, "ms": 0, "reason": "no borettslagsandel key was requested" },
        "annonser":         { "status": "empty",   "data": null, "ms": 22, "reason": "no Finn ad is mapped to this property or its units" }
      },
      "notes": [
        … the three standing caveats …,
        "0301-208-1-0-4 was answered from the matrikkelenhet 0301-208-1-0-0 — the buildings, the utleie and the parkering below belong to that whole property, not to that one unit.",
        "0301-208-1-0-0: only 1 of 2 shown buildings carry a registered bruksareal, so the area total covers those and no others — state the denominator."
      ],
      "properties": [
        {
          "requested": "0301-208-1-0-4",
          "new_unitkey": "0301-208-1-0-0",
          "answered_from": "parent_parcel",
          "requested_key_shape": "matrikkel",
          "adresse": "Akersgata 32, 0180 OSLO",
          "bydel": "St.Hanshaugen",
          "type": "Matrikkelenhet",
          "property_type": "sameie",
          "eiendomsareal_m2": 493.7,
          "antall_boliger": 0,
          "antall_seksjoner": 20,
          "solgt_url": "https://solgt.no/unit/0301-208-1-0-0",
          "bygninger": {
            "status": "registrert",
            "antall": 2,
            "antall_vist": 2,
            "antall_med_registrert_areal": 1,
            "bruksareal_totalt_m2": 3879,
            "bruksareal_bolig_m2": 0,
            "bruksareal_annet_m2": 3879,
            "antall_bygg_med_utvidelse": 0,
            "antall_sefrak": 0,
            "antall_fredet": 0,
            "typer": ["Annen lagerbygning", "Kontor- og adm.bygning rådhus"]
          },
          "bygningsliste": [
            {
              "bygningsnummer": 80471297,
              "type": "Kontor- og adm.bygning rådhus",
              "type_kode": "311",
              "status": "Tatt i bruk",
              "status_dato": "1934-01-01T00:00:00",
              "areal": {
                "areal_status": "registrert",
                "bruksareal_totalt_m2": 3879,
                "bruksareal_bolig_m2": 0,
                "bruksareal_annet_m2": 3879
              },
              "etasjer": [
                { "etasjenummer": 1, "etasjeplan": "Kjelleretasje", "bokstav": "K", "bruksareal_totalt_m2": 534 },
                … 8 more, summing to the 3 879 above rather than adding to it …
              ],
              "etasjer_totalt": 9,
              "endringer": [],
              "heis": true,
              "opprinnelse": "Vanlig registrering"
            },
            {
              "bygningsnummer": 80475691,
              "type": "Annen lagerbygning",
              "status": "Bygningsnummer utgått",
              "areal": { "areal_status": "ikke_registrert", "bruksareal_totalt_m2": null }
            }
          ],
          "utleie":    { "status": "ingen_registrert", "antall": 0, "annonser": [] },
          "parkering": { "status": "ingen_registrert", "antall_anlegg": 0, "anlegg": [] },
          "siste_eierskifte": { "dato": "2018-06-19T19:00:00.000Z", "type": "Fusjon/Fisjon", "er_tvangssalg": false },
          "annonser":  { "status": "ingen_registrert", "antall": 0, "etter_type": {}, "annonser": [] }
        }
      ],
      "unresolved": []
    }

The point requested and new_unitkey are two different keys on the same row, and answered_from: "parent_parcel" is what stands between them and a wrong answer: 3 879 m² is the office block on Akersgata 32, not the apartment somebody asked about. Read the denominator too — antall_med_registrert_areal: 1 of 2 buildings, because the second one's area was never recorded and comes back ikke_registrert with a null rather than a 0 that would quietly join the sum. And the nine etasjer are a breakdown of the 3 879, not an addition to it.

Has anything been built onto it?

A shop building from 1939 with four registered changes on it. Three were carried out and one was not, and the whole job is telling them apart — the register keeps the cancelled application on the building forever, under the same field as the work that stands there today.

  1. get_property_facts

    {
      "name": "get_property_facts",
      "arguments": {
        "unitkeys": ["0301-32-479-0-0"]
      }
    }
    1 building(s) across 1 of 1 requested property.
    AREAL: bruksarealTotalt = bruksarealTilBolig + bruksarealTilAnnet … PÅBYGD: endringer[] records Tilbygg, Påbygg, Underbygg (all three ADD area) and Ombygging (an internal rebuild that does NOT). …
    
    {
      "status": "ok",
      "shown": 1,
      "total": 1,
      "budget": { "db_ms": 46, "hops": 2, "rows_cap": 50 },
      "notes": [
        … the three standing caveats …,
        "0301-32-479-0-0 has 1 extension(s) recorded as cancelled, demolished or with a lapsed bygningsnummer. They were NOT built and must never be reported as work that was done."
      ],
      "properties": [
        {
          "requested": "0301-32-479-0-0",
          "new_unitkey": "0301-32-479-0-0",
          "answered_from": "requested_key",
          "adresse": "Ullernchausséen 1, 0377 OSLO",
          "bydel": "Ullern",
          "property_type": "naeringseiendom",
          "eiendomsareal_m2": 1055.5,
          "antall_boliger": 4,
          "bygninger": {
            "status": "registrert",
            "antall": 1,
            "antall_vist": 1,
            "antall_med_registrert_areal": 1,
            "bruksareal_totalt_m2": 1470,
            "bruksareal_bolig_m2": 468,
            "bruksareal_annet_m2": 1002,
            "antall_boenheter": 4,
            "antall_bygg_med_utvidelse": 1,
            "antall_utvidelser_gjennomfort": 3,
            "antall_utvidelser_planlagt": 0,
            "antall_utvidelser_bortfalt": 1,
            "antall_ombygginger_gjennomfort": 0,
            "ukjente_endringsstatuser": [],
            "typer": ["Kjøpesenter varehus"]
          },
          "bygningsliste": [
            {
              "bygningsnummer": 80088728,
              "type": "Kjøpesenter varehus",
              "type_kode": "321",
              "status": "Tatt i bruk",
              "status_dato": "1939-01-01T00:00:00",
              "areal": {
                "areal_status": "registrert",
                "bruksareal_totalt_m2": 1470,
                "bruksareal_bolig_m2": 468,
                "bruksareal_annet_m2": 1002
              },
              "antall_boenheter": 4,
              "etasjer": [
                { "etasjenummer": 1, "etasjeplan": "Underetasje", "bokstav": "U", "bruksareal_totalt_m2": 425, "bruksareal_bolig_m2": 79, "bruksareal_annet_m2": 346 },
                … 4 more …
              ],
              "etasjer_totalt": 5,
              "endringer": [
                { "endring": "Underbygg", "utvidelse": true, "status": "Ferdigattest",   "utfall": "gjennomfort", "dato": "2024-10-03T00:00:00" },
                { "endring": "Påbygg",    "utvidelse": true, "status": "Tatt i bruk",    "utfall": "gjennomfort", "dato": "2002-07-16T00:00:00" },
                { "endring": "Påbygg",    "utvidelse": true, "status": "Tatt i bruk",    "utfall": "gjennomfort", "dato": "1994-01-17T00:00:00" },
                { "endring": "Tilbygg",   "utvidelse": true, "status": "Bygging avlyst", "utfall": "bortfalt",    "dato": "2016-12-12T00:00:00",
                  "historikk": [ { "status": "Rammetillatelse", "dato": "1990-10-08T00:00:00" }, { "status": "Bygging avlyst", "dato": "2016-12-12T00:00:00" } ] }
              ],
              "endringer_totalt": 4,
              "sefrak": false,
              "fredet": false,
              "vannforsyning": "Tilkn. off. vannverk"
            }
          ],
          "utleie":    { "status": "ingen_registrert", "antall": 0, "annonser": [] },
          "parkering": { "status": "ingen_registrert", "antall_anlegg": 0, "anlegg": [] },
          "siste_eierskifte": { "dato": "2018-04-18T19:00:00.000Z", "type": "Fusjon/Fisjon", "er_tvangssalg": false },
          "annonser":  { "status": "ingen_registrert", "antall": 0, "etter_type": {}, "annonser": [] }
        }
      ],
      "unresolved": []
    }

The point Four changes, and the honest sentence is "three extensions were built and a fourth was applied for and cancelled" — antall_utvidelser_gjennomfort: 3 beside antall_utvidelser_bortfalt: 1. The Tilbygg on the last row has a Rammetillatelse from 1990 and a Bygging avlyst from 2016: reading endring: "Tilbygg" without utfall turns a permission that lapsed after twenty-six years into work that stands there. The area split matters here too — 1 470 m² is 468 bolig plus 1 002 annet, so "a 1 470 m² shop" and "a 468 m² home" are both in this building and neither is the whole of it. siste_eierskifte is the last change of hands and nothing more; the transfers behind it are get_conveyances.

From a company name to its portfolio

Two companies are registered under this exact name. The tool resolves which of them actually holds property, and hands the identifier on.

  1. resolve_owner

    {
      "name": "resolve_owner",
      "arguments": {
        "name": "AMT EIENDOM AS"
      }
    }
    "AMT EIENDOM AS" resolves to exactly one party holding property; use `next` and answer (1 other same-named company holds nothing).
    `holdings.total` is the number of properties each party is registered on and `holdings.kommuner` says where. …
    
    {
      "status": "ok",
      "shown": 1,
      "total": 2,
      "next": { "get_owner_portfolio": { "orgnr": "985836809" } },
      "resolution": "unique",
      "query": { "name": "AMT EIENDOM AS", "parties_matched": 2 },
      "candidates": [
        {
          "navn": "AMT EIENDOM AS",
          "type": "JuridiskPerson",
          "orgnr": "985836809",
          "grunnbok_id": 9631997,
          "holdings": {
            "parcels": 3,
            "sub_units": 4,
            "total": 7,
            "kommuner": [ { "nummer": "3101", "navn": "HALDEN" } ]
          }
        }
      ]
    }
  2. get_owner_portfolio

    next.get_owner_portfolio, unchanged. Had resolution been ambiguous, next would have been empty on purpose and the right move would be to ask which party is meant.

    {
      "name": "get_owner_portfolio",
      "arguments": {
        "orgnr": "985836809"
      }
    }
    AMT EIENDOM AS is registered on 7 properties (3 whole matrikkelenhet(er), 4 seksjon/andel); showing 7 on page 0.
    `shown` is this page; `total` is the whole portfolio. …
    
    {
      "status": "ok",
      "shown": 7,
      "total": 7,
      "next": {
        "get_owners":      { "unitkeys": ["3101-21-124-0-0", "3101-62-308-0-0", … ] },
        "get_conveyances": { "unitkeys": ["3101-21-124-0-0", "3101-62-308-0-0", … ] }
      },
      "owner": {
        "grunnbok_id": 9631997,
        "navn": "AMT EIENDOM AS",
        "org_number": "985836809",
        "type": "JuridiskPerson"
      },
      "page": 0,
      "page_size": 25,
      "has_more": false,
      "properties": [
        {
          "new_unitkey": "3101-21-124-0-0",
          "level": "parcel",
          "address": "Bukteløkka 31, 1794 SPONVIKA",
          "stake": { "prosent": 100, "type": "Eiendomsrett", "teller": 100, "nevner": 100 },
          "owned_via": "parcel",
          "read_from": { "new_unitkey": "3101-21-124-0-0", "property_type": "tomt" }
        }
        … 6 more, including 4 seksjoner on 3101-62-308-0-0 …
      ]
    }

The point A name is not an identity. Here it happened to resolve, and the answer still says so: two parties carry the name, one holds property. When both hold property, resolution is ambiguous, next is deliberately empty, and merging their portfolios would produce a confident answer about the wrong company.

From a property to its heftelser

get_encumbrances has no address form at all: it takes registerenhet ids and a level, and both come out of resolve_property. This is the add-on family — a key without it does not see the tool.

  1. resolve_property

    The same first hop as above — resolve once, then choose which next you need.

    {
      "name": "resolve_property",
      "arguments": {
        "new_unitkey": "0301-208-1-0-4"
      }
    }
    {
      "status": "ok",
      "next": {
        …
        "get_encumbrances": { "registerenhet_ids": [4112100], "level": "unit" }
      }
    }
  2. get_encumbrances

    {
      "name": "get_encumbrances",
      "arguments": {
        "registerenhet_ids": [4112100],
        "level": "unit"
      }
    }
    10 heftelse(r) on 1 registerenhetsrett(er) and 1 current andel(er) at unit level; showing 10.
    These are the heftelser on this seksjon or borettslagsandel's own rett. Heftelser registered on the parent parcel (shared servitutter, felles pant) are NOT included — resolve the parcel and ask again for those.
    A Tvangsforretning row is an utlegg (utleggsforretning/utpanting), not a forced sale. … Utlegg are covered both ways: on the property's own rett, and on a single co-owner's andel, which carry `burdens_andeler` with the share. …
    
    {
      "status": "ok",
      "shown": 10,
      "total": 10,
      "level": "unit",
      "resolution": {
        "requested_ids": [4112100],
        "retter": [ { "registerenhet_id": 4112100, "rett_id": 119409070, "rett_type": "Eiendomsrett" } ],
        "andeler": [ { "andel_id": 119409993, "rett_id": 119409070, "registerenhet_id": 4112100 } ],
        "ids_without_rett": []
      },
      "totals": {
        "antall": 10,
        "antall_pant": 0,
        "antall_tvangsforretninger": 0,
        "antall_tvangsforretninger_paa_andel": 0,
        "antall_servitutter": 10,
        "antall_anmerkninger": 0,
        "antall_andre": 0,
        "andre_typer": [],
        "antall_historiske": 0,
        "pant_total": null,
        "andre_valutaer": []
      },
      "encumbrances": [
        {
          "group": "servitutt",
          "type": "Servitutt",
          "rettsstiftelsestype": "ERKLÆRING/AVTALE",
          "historic": false,
          "amounts": [],
          "texts": [ { "type": "Bestemmelse om benyt…" } ]
        }
        … 9 more …
      ]
    }

The point The note is part of the answer: these are the seksjon's own heftelser, and the parcel's shared servitutter and felles pant are not in them. To cover both you resolve the parcel and ask a second time — the tool will not quietly merge two different registrations for you.

What has been paid, and what has not

The transfer history of the same seksjon. Both registered transfers carry no price — which is normal, and is not a sale for nothing.

  1. get_conveyances

    {
      "name": "get_conveyances",
      "arguments": {
        "unitkeys": ["0301-208-1-0-4"],
        "limit": 3
      }
    }
    2 overdragelse(r) across 1 property; showing 2.
    Buyers and sellers are narrowed to the andeler that belong to THIS registerenhet. Parties are named as tinglyst; no fødselsnummer exists anywhere in this answer.
    
    {
      "status": "ok",
      "shown": 2,
      "total": 2,
      "next": { "get_encumbrances": { "registerenhet_ids": [4112100], "level": "unit" } },
      "properties": [
        {
          "new_unitkey": "0301-208-1-0-4",
          "level": "unit",
          "type": "Seksjon",
          "solgt_url": "https://solgt.no/unit/0301-208-1-0-4",
          "totals": {
            "antall": 2,
            "antall_med_pris": 0,
            "antall_uten_pris": 2,
            "etter_omsetningstype": [ { "type": "Annet", "antall": 1 }, { "type": "Uoppgitt", "antall": 1 } ],
            "siste": { "dato": "2000-11-27", "pris": null, "omsetningstype": "Annet" }
          },
          "next": { "get_encumbrances": { "registerenhet_ids": [4112100], "level": "unit" } },
          "transfers": [
            {
              "registered_at": "2000-11-27",
              "document": "70608/2000",
              "document_status": "Tinglyst",
              "transfer_type": "Annet",
              "rettsstiftelsestype": "HJEMMEL TIL EIENDOMSRETT",
              "price": null,
              "doc_fee": { "amount": 10850, … }
            }
            … 1 more …
          ]
        }
      ]
    }

The point antall_uten_pris: 2 and price: null twice. Gave, arv, uskifte, fusjon and old registrations carry no vederlag, so the absence of a price is a property of the transfer type — never a sale for 0 kroner, and never an input to a valuation. Dates are the Norwegian calendar day the document was registered, not a timestamp to convert, and each property row carries its own next — so the heftelser hop for that one property is already assembled for you.

An utlegg against one co-owner, not against the property

"Er det utlegg på eiendommen?" is a question with two different right answers, and the difference matters to whoever is buying. Nearly half of all utlegg hang on a single co-owner's share rather than on the property itself.

  1. get_encumbrances

    The id comes from resolve_property.next.get_encumbrances, like every other call to this tool.

    {
      "name": "get_encumbrances",
      "arguments": {
        "registerenhet_ids": [3001287],
        "level": "parcel"
      }
    }
    23 heftelse(r) on 1 registerenhetsrett(er) and 4 current andel(er) at parcel level; showing 23.
    These are the heftelser on the parcel itself. Every seksjon and borettslagsandel on it has its OWN registerenhetsrett with its own heftelser, which are NOT included here …
    … 7 of the utlegg burden ONE co-owner's andel rather than the property itself — each carries `burdens_andeler` with the share it attaches to. …
    
    {
      "status": "ok",
      "shown": 23,
      "total": 23,
      "level": "parcel",
      "totals": {
        "antall": 23,
        "antall_pant": 0,
        "antall_tvangsforretninger": 7,
        "antall_tvangsforretninger_paa_andel": 7,
        "antall_servitutter": 16,
        "antall_anmerkninger": 0,
        "antall_andre": 0,
        "andre_typer": [],
        "antall_historiske": 0,
        "pant_total": null,
        "andre_valutaer": []
      },
      "encumbrances": [
        {
          "group": "tvangsforretning",
          "type": "Tvangsforretning",
          "rettsstiftelsestype": "UTLEGGSFORRETNING",
          "historic": false,
          "amounts": [ { "amount": 79835, "currency": "NOK" } ],
          "amount_total": { "amount": 79835, "currency": "NOK" },
          "burdens_andeler": [
            { "andel_id": 117961001, "rett_id": 117960121, "registerenhet_id": 3001287, "share": "1/4" }
          ],
          "also_attaches_to_other_andeler": 1,
          "rettighetshavere": []
        }
        … 6 more utlegg, and 16 servitutter …
      ]
    }

The point antall_tvangsforretninger: 7 and antall_tvangsforretninger_paa_andel: 7 — every one of them burdens a share, not the property. burdens_andeler names the share (1/4), and also_attaches_to_other_andeler counts the shares on other properties the same document reaches, which belong to those properties rather than to this one. The honest sentence is "one co-owner has an utlegg on their quarter share", never "the property has seven encumbrances" and never "the property is being sold by force".

Counting landbrukseiendommer in a municipality

naringsgruppe asks what the buildings on a parcel are used for. mode: "count" answers in the database, without reading a single property row.

  1. search_properties

    {
      "name": "search_properties",
      "arguments": {
        "kommune": "Ringebu",
        "naringsgruppe": "landbruk",
        "mode": "count",
        "group_by": "property_type"
      }
    }
    743 matching properties across 3 property_type group(s) — counted in the database, no rows read.
    
    {
      "status": "ok",
      "shown": 0,
      "total": 743,
      "notes": [
        "næringsgruppe matched a property with AT LEAST ONE building registered as \"Jordbruk, skogbruk og fiske\". A farm normally also has a dwelling and outbuildings, so this is the right rule — but it means a single building can carry the match: read `bygninger.i_naringsgruppen` against `bygninger.totalt` and `bolig_antall` before describing what the property is.",
        "NOT MATCHING IS NOT A NO. Of the 8678 properties this search covered, 2144 (24.7 %) could not be assessed by the næringsgruppe filter at all — 2025 have no registered building and 119 have buildings the register never classified. Land without a building is the ordinary case for fields and forest, so this is a MINIMUM, and it must never be presented as the complete set."
      ],
      "sections": {
        "count": { "status": "ok", "data": { "total": 743 }, "ms": 303 },
        "rows":  { "status": "empty", "reason": "mode=\"count\" — the counts come from the database; no property was read" },
        "dekning": { "status": "ok", "data": { "ikke_vurderbare": 2144 } }
      }
    }

The point 743 is a floor, not a total, and the answer says so before you can misread it: a quarter of the municipality's properties have no registered building to classify at all. Land without a building is the ordinary case for fields and forest.

Bygårder with at least four dwellings and at most two owners

«Alle useksjonerte bygårder i Oslo med minst 4 boligbruksenheter og maks 2 eiere» — the three conditions are arguments, so the set is filtered in the database. mode: "count" sizes it first; mode: "dataset" with the same arguments stores every row.

  1. search_properties

    min_bruksenheter is the registered count of bolig bruksenheter; max_eiere the registered owners of the matrikkelenhet. A property with no registered owner is not «0 owners» — it is reported under dekning and never matched.

    {
      "name": "search_properties",
      "arguments": {
        "kommune": "Oslo",
        "property_type": "bygaard",
        "seksjonert": false,
        "min_bruksenheter": 4,
        "max_eiere": 2,
        "mode": "count"
      }
    }
    1230 matching properties in Oslo — counted in the database, no rows read.
    
    {
      "status": "ok",
      "shown": 0,
      "total": 1230,
      "notes": [
        "min/max_bruksenheter bounded the register's count of BOLIG bruksenheter — shops, garages and boder on the same property are bruksenheter too and are NOT in that count. A property with no registered bruksenhet was never tested.",
        "min/max_eiere counted the registered owners (hjemmelshavere) of the MATRIKKELENHET. A company is one owner whatever its shareholders; a seksjonert building's flat owners sit one level down and are not counted; a property with no registered owner was never tested. …",
        "NOT MATCHING IS NOT A NO. Of the 1535 properties this search covered, 30 (2 %) could not be assessed by the bruksenheter and eiere filters at all — 0 have no registered bruksenhet, 30 have no registered owner (a parcel blind to several terms is counted once). This is a MINIMUM, and it must never be presented as the complete set. …"
      ],
      "query": {
        "scope": "kommune",
        "kommune": ["Oslo"],
        "property_type": ["bygaard"],
        "seksjonert": false,
        "bruksenheter": { "min": 4, "max": null },
        "eiere": { "min": null, "max": 2 },
        "bruksareal_m2": null,
        "mode": "count"
      },
      "count": { "total": 1230, "group_by": null, "breakdown": null, "breakdown_truncated": false },
      "dekning": {
        "eiendommer_vurdert": 1535,
        "uten_bruksenheter": 0,
        "uten_registrert_eier": 30,
        "uten_registrert_bruksareal": null,
        "ikke_vurderbare": 30,
        "andel_ikke_vurderbar_prosent": 2
      },
      "sections": {
        "count": { "status": "empty", "reason": "counted by the building coverage pass — one scan answers the total and the coverage" },
        "dekning": { "status": "ok", "data": { "ikke_vurderbare": 30 }, "ms": 273 }
      }
    }

The point 1 230 of the 1 535 useksjonerte bygårder meet both bounds, and the 30 with no registered owner are neither in nor out — dekning says so. The spreadsheet is the same call with mode: "dataset": the filters travel in the arguments, never applied to a page by eye.

What the business does, and whose name is over the door

Two national questions that sound like one. The first asks the register what a business does; the second asks what it is called. Both are answered as counts and a distribution, because a national answer is never a page of rows.

  1. search_commercial_properties

    47.11 is grocery retail. Counting stops before the matrikkel and the share register, so the whole country answers in about a second.

    {
      "name": "search_commercial_properties",
      "arguments": {
        "naeringskode": "47.11",
        "mode": "count",
        "group_by": "kjede"
      }
    }
    Returned 4815 eiendom(mer) for 6140 virksomhet(er) i hele landet.
    
    {
      "status": "ok",
      "shown": 0,
      "total": 4815,
      "next": {},
      "budget": { "db_ms": 1064, "hops": 2, "rows_cap": 0 },
      "notes": [
        "869 av 6140 virksomheter er ikke koblet til en matrikkelenhet og mangler derfor i lista. De er ikke fraværende fra markedet — de er ikke stedfestet.",
        "Leieforhold er UTLEDET av eierskap, ikke lest fra en leiekontrakt. Solgt har ikke noe kommersielt leietakerregister; …",
        "mode:\"count\" leser ikke matrikkelen eller aksjonærregisteret — ingen eier, ingen leieforhold. Be om group_by:\"leieforhold\" med kommune eller fylke for fordelingen, eller mode:\"rows\" for eierne på hver enkelt eiendom."
      ],
      "scope": "hele landet",
      "naeringskode": "47.11",
      "brand": [],
      "virksomheter": 6140,
      "eiendommer": 4815,
      "dekning": {
        "virksomheter_matchet": 6140,
        "virksomheter_uten_eiendomskobling": 869,
        "koblingsgrad_prosent": 85.8,
        "koblinger_under_full_sikkerhet": 233
      },
      "group_by": "kjede",
      "fordeling": {
        "COOP PRIX": 195,
        "KIWI": 619,
        "utenfor kjedene": 2031,
        "MENY": 121,
        "REMA 1000": 627,
        "COOP EXTRA": 475,
        "JOKER": 184,
        "COOP OBS + COOP (annet)": 2,
        "NÆRBUTIKKEN": 20,
        "SPAR/EUROSPAR": 159,
        "COOP MEGA": 49,
        "BUNNPRIS": 124,
        … 36 more, most of them a handful of properties where two or three chains share one address …
      }
    }
  2. search_commercial_properties

    The same tool asked the other question: one name over the door, no industry code at all.

    {
      "name": "search_commercial_properties",
      "arguments": {
        "brand": ["KIWI"],
        "mode": "count"
      }
    }
    Returned 643 eiendom(mer) for 700 virksomhet(er) i hele landet.
    
    {
      "status": "ok",
      "shown": 0,
      "total": 643,
      "next": {},
      "scope": "hele landet",
      "naeringskode": null,
      "brand": ["KIWI"],
      "virksomheter": 700,
      "eiendommer": 643,
      "dekning": {
        "virksomheter_matchet": 700,
        "virksomheter_uten_eiendomskobling": 54,
        "koblingsgrad_prosent": 92.3,
        "koblinger_under_full_sikkerhet": 8
      },
      "group_by": null,
      "fordeling": null
    }

The point utenfor kjedene: 2031. Of the 4 815 properties with a grocery business on them, 2 031 carry none of the named chains — the kiosks, the independents, the local grocers. "Every grocery shop" is the industry code and "every chain shop" is the brand list, and answering one when the other was asked produces a number nothing in the output would flag as wrong. The brand call is not a subset of the code either: 643 properties carry a KIWI by name against the 619 the grocery code finds, because a business can be registered under some other code than the one its shop suggests. And note what neither call returned — shown: 0, twice. Rows are a municipality or a county at a time.

Every grocery property in a municipality, and who is behind them

The rows form, scoped to one kommune. Three of the twenty-five rows on this page are shown, and they are three different answers to the only question that matters here: does the shop sit in a building its own group owns?

  1. search_commercial_properties

    {
      "name": "search_commercial_properties",
      "arguments": {
        "naeringskode": "47.11",
        "kommune": "Bergen",
        "page_size": 25
      }
    }
    Returned 258 eiendom(mer) for 302 virksomhet(er) i BERGEN.
    
    {
      "status": "ok",
      "shown": 25,
      "total": 258,
      "next": {
        "get_owners":            { "unitkeys": ["4601-105-40-0-0", "4601-11-247-0-0", … ] },
        "get_property_facts":    { "unitkeys": ["4601-105-40-0-0", "4601-11-247-0-0", … ] },
        "get_property_tenancy":  { "unitkeys": ["4601-105-40-0-0", "4601-11-247-0-0", … ] }
      },
      "budget": { "db_ms": 1021, "hops": 8, "rows_cap": 25 },
      "sections": {
        "matrikkel": { "status": "ok", "ms": 31 },
        "co_tenants": { "status": "ok", "ms": 52 },
        "konsern": { "status": "ok", "ms": 787 },
        "eierkjede": { "status": "ok", "ms": 1 },
        "regnskap": { "status": "ok", "ms": 27 }
      },
      "notes": [
        "13 av 302 virksomheter er ikke koblet til en matrikkelenhet og mangler derfor i lista. De er ikke fraværende fra markedet — de er ikke stedfestet.",
        "Leieforhold er UTLEDET av eierskap, ikke lest fra en leiekontrakt. Solgt har ikke noe kommersielt leietakerregister; …",
        "Regnskapstallene er SELSKAPSREGNSKAP (regnskapstype SELSKAP). Kilden har ingen konserntall overhodet, samtidig som den merker 57 585 selskaper som morselskap. …",
        "97,7 % av selskapene leverer forkortet regnskap (små foretak). Derfor vises samlet gjeld og ikke fordelingen på kort og lang sikt: langsiktig gjeld mangler i over halvparten av regnskapene, og det er nettopp der en utleiers pantegjeld ville stått. …",
        "Manglende driftsinntekter er som regel NULL, ikke ukjent — Brønnøysund utelater feltet i stedet for å skrive 0. `omsetning_kilde` skiller de tre tilfellene: "oppgitt", "utledet_null" og "ukjent". …",
        "Hvert tall står sammen med sitt eget regnskapsår, og `aar` er REGNSKAPSÅRET — ikke innleveringsåret. De aller fleste selskapene har foreløpig bare ett år i basen, så ingen utvikling eller trend kan leses ut av dette."
      ],
      "scope": "BERGEN",
      "naeringskode": "47.11",
      "brand": [],
      "page": 0,
      "page_size": 25,
      "has_more": true,
      "dekning": {
        "virksomheter_matchet": 302,
        "virksomheter_uten_eiendomskobling": 13,
        "koblingsgrad_prosent": 95.7,
        "koblinger_under_full_sikkerhet": 15,
        "matrikkelenheter_pa_siden": 25,
        "matrikkelenheter_ikke_funnet": 1
      },
      "tenancy_summary": {
        "selveier": 0,
        "nærstående": 2,
        "ekstern utleier": 17,
        "eierkjede uoppløst": 5,
        "ukjent": 1
      },
      "properties": [
        … 13 rows …
        {
          "matrikkelnumre": ["4601-121-320-0-0"],
          "adresse": "Nordåsdalen 42, 5235 RÅDAL",
          "leietaker_kjede": ["KIWI"],
          "driftsselskap": [ { "navn": "NG KIWI VEST AS AVD 805 NORDÅS", "orgnr": "929616863" } ],
          "morselskap":    [ { "navn": "NG KIWI VEST AS", "orgnr": "979443137" } ],
          "andre_virksomheter": { "navn": [ … ], "totalt": 28 },
          "spv": { "navn": "STATENS VEGVESEN", "orgnr": "971032081", "kilde": "matrikkelenhet", "seksjon_hjemmelshavere": null },
          "overste_eier": null,
          "leieforhold": { "naerstaende_via": null, "er_utledet": true, "klasse": "eierkjede uoppløst" },
          "tomteareal": { "per_matrikkelenhet": [ { "matrikkelnummer": "4601-121-320-0-0", "m2": 24842.3 } ], "sum_m2": 24842.3 },
          "bra": { "m2": null, "grunnlag": "sum bruksareal for alle bygg på eiendommen — ikke butikkarealet" },
          "merknader": [
            "bruksareal ikke registrert i matrikkelen",
            "2 bygg holdt utenfor arealet (revet, utgått, avlyst eller flyttet)"
          ]
        },
        … 6 rows …
        {
          "matrikkelnumre": ["4601-124-97-0-0"],
          "adresse": "Vadmyrveien 48, 5172 LODDEFJORD",
          "forretningsadresse": "Vadmyrveien 48",
          "kommune": "BERGEN",
          "leietaker_kjede": ["COOP EXTRA"],
          "driftsselskap": [ { "navn": "EXTRA VADMYRA", "orgnr": "973160036" } ],
          "morselskap":    [ { "navn": "COOP HORDALAND SA", "orgnr": "982594421" } ],
          "andre_virksomheter": { "navn": [], "totalt": 0 },
          "spv": {
            "navn": "CEV VADMYRA AS", "orgnr": "892552762", "kilde": "matrikkelenhet", "seksjon_hjemmelshavere": null,
            "regnskap": {
              "status": "levert", "siste_aar": 2025, "sjekket": "2026-08-14",
              "regnskap": [
                {
                  "aar": 2025, "periode": { "fra": "2025-01-01", "til": "2025-12-31" }, "valuta": "NOK",
                  "omsetning": 1336768, "omsetning_kilde": "oppgitt",
                  "driftsresultat": 861380, "aarsresultat": -157207,
                  "egenkapital": 584207, "sum_eiendeler": 26418319, "sum_gjeld": 25834112,
                  "egenkapitalandel_prosent": 2.2, "negativ_egenkapital": false,
                  "uten_omsetning": false, "avviklingsregnskap": false,
                  "smaa_foretak": true, "morselskap": false
                }
              ],
              "merknader": []
            }
          },
          "overste_eier": {
            "navn": "COOP HORDALAND SA", "orgnr": "982594421", "form": "samvirke",
            "andel_prosent": 100, "entydig": true, "tied_holders": null, "ledd": 2,
            "kilde": "konsernrollup", "oppdatert": "2026-08-18",
            "regnskap": {
              "status": "levert", "siste_aar": 2024, "sjekket": "2026-08-14",
              "regnskap": [
                {
                  "aar": 2024, "periode": { "fra": "2024-01-01", "til": "2024-12-31" }, "valuta": "NOK",
                  "omsetning": 4261219000, "omsetning_kilde": "oppgitt",
                  "driftsresultat": 112255000, "aarsresultat": 124768000,
                  "egenkapital": 739923000, "sum_eiendeler": 1810259000, "sum_gjeld": 1070334000,
                  "egenkapitalandel_prosent": 40.9, "negativ_egenkapital": false,
                  "uten_omsetning": false, "avviklingsregnskap": false,
                  "smaa_foretak": false, "morselskap": true
                }
              ],
              "merknader": [
                "registrert som morselskap, men tallene er selskapets egne — konsernregnskap finnes ikke i kilden"
              ]
            }
          },
          "leieforhold": {
            "klasse": "nærstående",
            "naerstaende_via": { "navn": null, "orgnr": "982594421" },
            "er_utledet": true
          },
          "tomteareal": { "per_matrikkelenhet": [ { "matrikkelnummer": "4601-124-97-0-0", "m2": 2509 } ], "sum_m2": 2509 },
          "bra": { "m2": 1383, "grunnlag": "sum bruksareal for alle bygg på eiendommen — ikke butikkarealet" },
          "merknader": ["1 bygg holdt utenfor arealet (revet, utgått, avlyst eller flyttet)"]
        },
        … 2 rows …
        {
          "matrikkelnumre": ["4601-13-127-0-0"],
          "adresse": "Jacob Kjødes veg 2A, 5232 PARADIS",
          "adresser_totalt": 8,
          "forretningsadresse": "Jacob Kjødes veg 2E",
          "leietaker_kjede": ["REMA 1000"],
          "driftsselskap": [ { "navn": "REMA 1000 PARADIS", "orgnr": "925100994" } ],
          "morselskap":    [ { "navn": "MORTEN IVERSEN AS", "orgnr": "919026987" } ],
          "andre_virksomheter": { "navn": [ … ], "totalt": 50 },
          "spv": { "navn": "NORDIC RESIDENTIAL PROPERTIES PARADISALLÉEN AS", "orgnr": "920618448", "kilde": "seksjon", "seksjon_hjemmelshavere": 206 },
          "overste_eier": {
            "navn": "HAAS HOLDING AS", "orgnr": "825906142", "form": "norsk selskap",
            "andel_prosent": 6.96, "entydig": false, "tied_holders": 2, "ledd": 3,
            "kilde": "konsernrollup", "oppdatert": "2026-08-18"
          },
          "leieforhold": { "naerstaende_via": null, "er_utledet": true, "klasse": "ekstern utleier" },
          "bra": { "m2": 18312, "grunnlag": "sum bruksareal for alle bygg på eiendommen — ikke butikkarealet" },
          "merknader": [
            "eiendommen er seksjonert – hjemmelshaver står på seksjonene (206 part(er))",
            "eierkjeden ender i 2 likeverdige eiere – den navngitte er én av dem, ikke en fastslått kontrollerende eier",
            "største eier 6.96 % – ikke nødvendigvis kontrollerende",
            "13 bygg holdt utenfor arealet (revet, utgått, avlyst eller flyttet)"
          ]
        }
        … 1 more row on this page, and 233 more properties behind `has_more` …
      ]
    }

The point Three rows, three different statements. The COOP EXTRA is nærstående: the operator's parent and the landlord's chain meet at the same company, and naerstaende_via carries its organisasjonsnummer — 982594421, the operator's parent — so the inference can be checked rather than taken on trust. The REMA is ekstern utleier with entydig: false — the landlord's chain ends in two equal holders, so HAAS HOLDING AS is one of them and not an established controlling owner, and 6.96 % is a share at the top of that chain rather than a stake in the property. The KIWI is eierkjede uoppløst, which is the absence of a finding: the deed is held by Statens vegvesen, there is no share chain to walk, and calling that an external landlord would state something nobody established. Read bra the same way: 18 312 m² is the whole seksjonerte property — the deed sits on its seksjoner, 206 hjemmelshavere of them — and not the supermarket, while the KIWI's is null because the matrikkel records no floor area for that property at all. And the accounts turn nærstående into a number: CEV VADMYRA AS holds 26.4 M in assets against 25.8 M of debt, an egenkapitalandel_prosent of 2.2 — a landlord with almost no cushion, sitting under a group whose own filing shows 40.9 %. Read COOP HORDALAND's figures for what they are, though: morselskap: true with the merknad beside it, because the source holds no consolidated accounts at all, so 1.81 bn in assets is the parent company alone and not the group's estate. smaa_foretak: true on the SPV is the other half of that caution — an abbreviated filing, which is why sum_gjeld is shown whole and never split into the long-term line a building's mortgage would sit in. Finally dekning — 13 of the 302 businesses have no property link, so they are missing from these rows rather than absent from Bergen.

Owner-occupied or tenant, across a whole municipality

The rows answer above showed three properties and told you what each one is. This asks the same question of all 258 at once — and it is the one breakdown that costs something, because there is no way to know whether a shop owns its building without resolving the deed and both ownership chains for every single property.

  1. search_commercial_properties

    A kommune or a fylke is required for this one breakdown, and only this one — kommune and kjede answer nationally.

    {
      "name": "search_commercial_properties",
      "arguments": {
        "naeringskode": "47.11",
        "kommune": "Bergen",
        "mode": "count",
        "group_by": "leieforhold"
      }
    }
    Returned 258 eiendom(mer) for 302 virksomhet(er) i BERGEN.
    
    {
      "status": "ok",
      "shown": 0,
      "total": 258,
      "next": {},
      "budget": { "db_ms": 1040, "hops": 10, "rows_cap": 0 },
      "notes": [
        "13 av 302 virksomheter er ikke koblet til en matrikkelenhet og mangler derfor i lista. …",
        "Leieforhold er UTLEDET av eierskap, ikke lest fra en leiekontrakt. …",
        "group_by:\"leieforhold\" leste matrikkelen og aksjonærregisteret for alle 258 eiendommene i omfanget, så fordelingen dekker HELE omfanget — ikke én side. …"
      ],
      "scope": "BERGEN",
      "naeringskode": "47.11",
      "brand": [],
      "virksomheter": 302,
      "eiendommer": 258,
      "dekning": {
        "virksomheter_matchet": 302,
        "virksomheter_uten_eiendomskobling": 13,
        "koblingsgrad_prosent": 95.7,
        "koblinger_under_full_sikkerhet": 15
      },
      "group_by": "leieforhold",
      "fordeling": {
        "selveier": 3,
        "nærstående": 15,
        "ekstern utleier": 160,
        "eierkjede uoppløst": 78,
        "ukjent": 2
      }
    }

The point eierkjede uoppløst: 78 is nearly a third of the municipality's grocery properties, and it is the number this answer exists to keep honest: those are chains we could not resolve, not landlords established to be at arm's length. Add them to the 160 and you have reported 238 external landlords, 78 of which nobody established. The five classes are the same five the rows answer puts on each property and they are computed the same way — the difference is the denominator: this one is all 258 properties in Bergen, while a rows answer's tenancy_summary counts the 25 on the page in front of you. Both are exact for what they cover, and neither is the other.

From an address to the businesses in the building

A shopping centre in Bergen. The second call takes the property key straight out of the first call's next — occupancy is recorded against the matrikkelenhet, which is exactly the level this address resolves to.

  1. resolve_property

    {
      "name": "resolve_property",
      "arguments": {
        "address": "Loddefjordveien 2",
        "kommune": "Bergen"
      }
    }
    Resolved 1 of 1 requested property via address (index `bruksenheter.adresse_1 + bruksenhet.adresse_1`).
    "Loddefjordveien 2" in kommune 4601 → 1 of 1 unit(s) at entrance Loddefjordveien 2. These units ARE the answer (level: parcel).
    
    {
      "status": "ok",
      "shown": 1,
      "total": 1,
      "next": {
        "get_conveyances":     { "unitkeys": ["4601-124-189-0-0"] },
        "get_owners":          { "unitkeys": ["4601-124-189-0-0"] },
        "get_property_facts":  { "unitkeys": ["4601-124-189-0-0"] },
        "get_innsyn_cases":    { "unitkeys": ["4601-124-189-0-0"], "level": "parcel" },
        "get_encumbrances":    { "registerenhet_ids": [2367430], "level": "parcel" }
      },
      "budget": { "db_ms": 25, "hops": 2, "rows_cap": 25 }
    }
  2. get_property_tenancy

    The key from next, unchanged. resolve_property has no tenancy entry of its own — every unitkey hop it hands out carries the same five-segment key, and that is the argument.

    {
      "name": "get_property_tenancy",
      "arguments": {
        "unitkeys": ["4601-124-189-0-0"]
      }
    }
    Returned 1 eiendom(mer) med virksomheter og eierskap.
    
    {
      "status": "ok",
      "shown": 1,
      "total": 1,
      "next": {
        "get_owners":         { "unitkeys": ["4601-124-189-0-0"] },
        "get_property_facts": { "unitkeys": ["4601-124-189-0-0"] }
      },
      "budget": { "db_ms": 1995, "hops": 15, "rows_cap": 25 },
      "notes": [
        "Leieforhold er UTLEDET av eierskap — hvem som eier driftsselskapet og hvem som eier bygget — ikke lest fra en leiekontrakt. Solgt har ikke noe kommersielt leietakerregister.",
        "Virksomhetene er de som er REGISTRERT på adressen i Enhetsregisteret. En bedrift kan være registrert uten å drive der, og en leietaker uten egen registrering mangler.",
        "Regnskapstallene er SELSKAPSREGNSKAP (regnskapstype SELSKAP). Kilden har ingen konserntall overhodet … tall for et morselskap dekker morselskapet ALENE.",
        "97,7 % av selskapene leverer forkortet regnskap (små foretak). Derfor vises samlet gjeld og ikke fordelingen på kort og lang sikt … Fravær av langsiktig gjeld betyr ikke at selskapet er gjeldfritt.",
        "Manglende driftsinntekter er som regel NULL, ikke ukjent — Brønnøysund utelater feltet i stedet for å skrive 0. …",
        "Hvert tall står sammen med sitt eget regnskapsår, og `aar` er REGNSKAPSÅRET — ikke innleveringsåret. …"
      ],
      "properties": [
        {
          "matrikkelnummer": "4601-124-189-0-0",
          "funnet": true,
          "adresse": "Loddefjordveien 2, 5171 LODDEFJORD",
          "kommune": "BERGEN",
          "virksomheter": [
            {
              "navn": "RAMSVIK FRISØR VESTKANTEN AS", "orgnr": "812341472", "kjede": null,
              "naeringskode": null, "naering": null, "morselskap": null
            },
            … 88 more …
            {
              "navn": "MENY VESTKANTEN", "orgnr": "971894652", "kjede": "MENY",
              "naeringskode": "47.110",
              "naering": "Detaljhandel med bredt vareutvalg med hovedvekt på nærings- og nytelsesmidler",
              "morselskap": { "navn": "NG MENY VEST AS", "orgnr": "979679971" }
            },
            … 6 more …
            {
              "navn": "OBS HYPERMARKED VESTKANTEN", "orgnr": "973160052", "kjede": "COOP OBS",
              "naeringskode": "47.110",
              "naering": "Detaljhandel med bredt vareutvalg med hovedvekt på nærings- og nytelsesmidler",
              "morselskap": { "navn": "COOP HORDALAND SA", "orgnr": "982594421" }
            },
            … 24 more …
            {
              "navn": "SATS VESTKANTEN", "orgnr": "982335159", "kjede": null,
              "naeringskode": "93.130", "naering": "Treningssentervirksomhet",
              "morselskap": { "navn": "SATS NORWAY AS", "orgnr": "892625522" }
            }
            … 20 more, from clothing shops and restaurants to a dental clinic, a driving school and a NAV office …
          ],
          "virksomheter_totalt": 142,
          "spv": {
            "navn": "Vestkanten AS", "orgnr": "928654931", "kilde": "matrikkelenhet", "seksjon_hjemmelshavere": null,
            "regnskap": {
              "status": "levert", "siste_aar": 2025, "sjekket": "2026-08-14",
              "regnskap": [
                {
                  "aar": 2025, "periode": { "fra": "2025-01-01", "til": "2025-12-31" }, "valuta": "NOK",
                  "omsetning": 189064886, "omsetning_kilde": "oppgitt",
                  "driftsresultat": 87232657, "aarsresultat": 57608011,
                  "egenkapital": 372926790, "sum_eiendeler": 853339932, "sum_gjeld": 480413140,
                  "egenkapitalandel_prosent": 43.7, "negativ_egenkapital": false,
                  "uten_omsetning": false, "avviklingsregnskap": false,
                  "smaa_foretak": false, "morselskap": true
                }
              ],
              "merknader": [
                "registrert som morselskap, men tallene er selskapets egne — konsernregnskap finnes ikke i kilden"
              ]
            }
          },
          "overste_eier": {
            "navn": "OLAV THON STIFTELSEN", "orgnr": "912868761", "form": "norsk selskap",
            "andel_prosent": 60.14, "entydig": true, "tied_holders": null, "ledd": 3,
            "kilde": "konsernrollup", "oppdatert": "2026-08-18",
            "regnskap": {
              "status": "levert", "siste_aar": 2025, "sjekket": "2026-08-14",
              "regnskap": [
                {
                  "aar": 2025, "periode": { "fra": "2025-01-01", "til": "2025-12-31" }, "valuta": "NOK",
                  "omsetning": 3523795904, "omsetning_kilde": "oppgitt",
                  "driftsresultat": 3479123668, "aarsresultat": 3573706139,
                  "egenkapital": 29116330724, "sum_eiendeler": 29251016029, "sum_gjeld": 134685305,
                  "egenkapitalandel_prosent": 99.5, "negativ_egenkapital": false,
                  "uten_omsetning": false, "avviklingsregnskap": false,
                  "smaa_foretak": false, "morselskap": true
                }
              ],
              "merknader": [
                "registrert som morselskap, men tallene er selskapets egne — konsernregnskap finnes ikke i kilden"
              ]
            }
          },
          "leieforhold": {
            "klasse": "nærstående",
            "naerstaende_via": { "navn": "VESTKANTEN AS", "orgnr": "928654931" },
            "er_utledet": true
          },
          "tomteareal_m2": 33815.1,
          "bra": { "m2": 54597, "grunnlag": "sum bruksareal for alle bygg på eiendommen — ikke butikkarealet" },
          "merknader": []
        }
      ]
    }

The point virksomheter_totalt: 142 is the number to quote; the named ones are what fits on a page. These are registrations, not leases — Enhetsregisteret records the address a business gave, so a company can appear here without trading here, and a tenant who never registered does not appear at all. A business with no naeringskode is one the sub-unit register does not classify, not one without a trade. bra: 54597 is the entire centre, which is the same field that would report a block of flats above a corner shop. And leieforhold: nærstående is inferred rather than read: naerstaende_via names Vestkanten AS — the registered owner itself — so at least one business here belongs to the landlord's own group. The regnskap block is what makes that landlord assessable rather than just named: 853 M in assets, 43.7 % equity, 189 M of revenue for the year 2025 — one entry in an array, carrying its own aar and periode, because one year is all the source holds for almost every company and a single year shows no direction. Both this company and OLAV THON STIFTELSEN carry morselskap: true, and the merknad on each says the same thing: these are the company's own figures, not the group's, because there is no consolidated filing to read.

Market statistics for a municipality

The aggregate side. No address, no row, no individual home — averages, counts and ratios over a window.

  1. summarize_sold_homes

    {
      "name": "summarize_sold_homes",
      "arguments": {
        "kommune_name": "Oslo",
        "from": "2026-01-01",
        "to": "2026-03-31",
        "housingtype": "Leilighet",
        "groupBy": "none",
        "format": "data"
      }
    }
    Returned 1 derived row(s) — aggregated statistics (no raw documents).
    
    {
      "status": "ok",
      "source": "Solgt.no — verified sold-home transactions (read-only, aggregated; no raw rows)",
      "window": { "field": "sold_date", "from": "2026-01-01T00:00:00.000Z", "to": "2026-03-31T23:59:59.999Z" },
      "filters": { "kommune_name": "Oslo", "housingtype": "Leilighet" },
      "groupBy": "none",
      "overall": {
        "num_sales": 5201,
        "price_per_sqm":        { "avg": 103363,  "min": 25477,   "max": 233945 },
        "sale_price_incl_debt": { "avg": 6256983, "min": 1650000, "max": 47500000 },
        "paid_vs_asking_ratio": { "avg": 1.0206,  "min": 0.6962,  "max": 1.4853 },
        "days_on_market":       { "avg": 30.8,    "min": 0,       "max": 1033 },
        "data_quality": { "price_per_sqm": 0, "sale_price_incl_debt": 0, "paid_vs_asking_ratio": 0, "days_on_market": 0 }
      },
      "metrics_legend": { … what each metric means … }
    }

The point data_quality counts, per metric, the provably impossible values excluded from its average — a sub-100k "sale", a 14 M kr/m². Here it is zero across the board, but num_sales always counts every transaction in the bucket, valid metric or not. The window is fixed rather than lastMonths: 3 so these numbers are reproducible; a rolling window answers about a different quarter every day.

How many homes were pulled, and is that a bigger share than before

«Trukket fra markedet» is a listing's third ending, next to selling and still being out there. The count on its own answers nothing — 261 out of what? — so the aggregate returns the stock it came out of and the share those two make. Two shapes of the same question: windows puts two Junes side by side, and groupBy "month" draws the trend — «er det flere annonser som trekkes fra markedet?» — with a share per month rather than a raw count that only tracks how big the market got. The last call is the follow-up — «og hvor stor andel ble solgt?» — asked as outcome "all", the same stock split three ways.

  1. summarize_homes_for_sale

    {
      "name": "summarize_homes_for_sale",
      "arguments": {
        "municipality_name": "Oslo",
        "outcome": "withdrawn",
        "groupBy": "none",
        "format": "data",
        "windows": [
          {
            "label": "juni 2025",
            "from": "2025-06-01",
            "to": "2025-06-30"
          },
          {
            "label": "juni 2026",
            "from": "2026-06-01",
            "to": "2026-06-30"
          }
        ]
      }
    }
    Returned 2 derived row(s) across 2 window(s) — aggregated statistics (no raw documents).
    
    {
      "batch": { "tool": "summarize_homes_for_sale", "window_count": 2, "note": "… `results[i]` belongs to `windows[i]` …" },
      "windows": [
        {
          "label": "juni 2025",
          "status": "ok",
          "from": "2025-06-01T00:00:00.000Z",
          "to": "2025-06-30T23:59:59.999Z",
          "hint": "inactive_1_inactive_date_1 + added_date_-1",
          "num_withdrawn": 158,
          "homes_on_market": 4768,
          "withdrawn_share": 0.0331
        },
        {
          "label": "juni 2026",
          "status": "ok",
          "from": "2026-06-01T00:00:00.000Z",
          "to": "2026-06-30T23:59:59.999Z",
          "hint": "inactive_1_inactive_date_1 + added_date_-1",
          "num_withdrawn": 252,
          "homes_on_market": 5507,
          "withdrawn_share": 0.0458
        }
      ],
      "results": [
        {
          "status": "ok",
          "source": "Solgt.no — resale listings WITHDRAWN from the market without a sale …, beside the stock of homes on the market in the same period.",
          "scope": {
            "withdrawn_in": "within window",
            "field": "inactive_date",
            "from": "2026-06-01T00:00:00.000Z",
            "to": "2026-06-30T23:59:59.999Z",
            "denominator": { "what": "homes on the market in the same period (the stock)", "lookback_months": 24 }
          },
          "outcome": "withdrawn",
          "groupBy": "none",
          "overall": {
            "num_withdrawn": 252,
            "homes_on_market": 5507,
            "withdrawn_share": 0.0458,
            "asking_price":     { "avg": 11120064, "min": 2703707, "max": 89000000 },
            "sqm_asking_price": { "avg": 106690,   "min": 35891,   "max": 279412 },
            "days_on_market":   { "avg": 102.1,    "min": 0,       "max": 1538 }
          },
          "metrics_legend": { … what each figure means, and what the denominator does not cover … }
        },
        { … juni 2025, same shape … }
      ]
    }
  2. search_homes_for_sale

    The same switch on the raw tool — the individual homes behind the 252, longest-suffering first.

    {
      "name": "search_homes_for_sale",
      "arguments": {
        "municipality_name": "Oslo",
        "outcome": "withdrawn",
        "from": "2026-06-01",
        "to": "2026-06-30",
        "sort_by": "days_on_market",
        "sort_dir": "desc",
        "pageSize": 3
      }
    }
    Returned 3 of 252 matching record(s) (page 0, pageSize 3 — more available).
    
    {
      "status": "ok",
      "source": "Solgt.no — resale listings WITHDRAWN from the market without a sale …. days_on_market is the time each home DID lie out, listed until pulled.",
      "outcome": "withdrawn",
      "window": { "field": "inactive_date", "from": "2026-06-01T00:00:00.000Z", "to": "2026-06-30T23:59:59.999Z" },
      "total": 252,
      "items": [
        {
          "new_unitkey": "0301-195-213-0-1",
          "address": "Vargveien 1F, 0139 OSLO",
          "bydelsnavn": "Nordstrand",
          "property_type": "Leilighet",
          "ownership_type": "Selveier",
          "sqm": 84,
          "build_year": 1984,
          "added_date": "2022-04-06T09:51:54.197Z",
          "withdrawn_date": "2026-06-22T09:09:00.000Z",
          "days_on_market": 1537,
          "asking_price": 7250000,
          "price_changes_count": 8,
          "finn_url": "https://www.finn.no/realestate/homes/ad.html?finnkode=253957983",
          "solgt_url": "https://solgt.no/unit/0301-195-213-0-1"
        },
        { … two more … }
      ]
    }
  3. summarize_homes_for_sale

    The other half of the question — «er det flere annonser som trekkes fra markedet?» is a trend, so it is groupBy "month" on the same switch, bucketed by when each home was pulled.

    {
      "name": "summarize_homes_for_sale",
      "arguments": {
        "municipality_name": "Oslo",
        "outcome": "withdrawn",
        "groupBy": "month",
        "from": "2026-01-01",
        "to": "2026-08-31",
        "format": "data"
      }
    }
    Returned 8 derived row(s) — aggregated statistics (no raw documents).
    
    {
      "status": "ok",
      "scope": { "withdrawn_in": "within window", "field": "inactive_date", "from": "2026-01-01T00:00:00.000Z", "to": "2026-08-31T23:59:59.999Z" },
      "outcome": "withdrawn",
      "groupBy": "month",
      "overall": {
        "num_withdrawn": 1441,
        "homes_on_market": 19562,
        "withdrawn_share": 0.0737,
        "months": 8,
        "avg_per_month": 180.1,
        "min_month": { "month": "2026-01", "num_withdrawn": 91 },
        "max_month": { "month": "2026-08", "num_withdrawn": 369 }
      },
      "breakdown": [
        { "month": "2026-01", "num_withdrawn":  91, "homes_on_market": 4078, "withdrawn_share": 0.0223, … },
        { "month": "2026-02", "num_withdrawn": 133, "homes_on_market": 3901, "withdrawn_share": 0.0341, … },
        { "month": "2026-03", "num_withdrawn": 135, "homes_on_market": 3963, "withdrawn_share": 0.0341, … },
        { "month": "2026-04", "num_withdrawn": 104, "homes_on_market": 4560, "withdrawn_share": 0.0228, … },
        { "month": "2026-05", "num_withdrawn": 184, "homes_on_market": 5529, "withdrawn_share": 0.0333, … },
        { "month": "2026-06", "num_withdrawn": 251, "homes_on_market": 5515, "withdrawn_share": 0.0455, … },
        { "month": "2026-07", "num_withdrawn": 174, "homes_on_market": 3892, "withdrawn_share": 0.0447, … },
        { "month": "2026-08", "num_withdrawn": 369, "homes_on_market": 5498, "withdrawn_share": 0.0671, … }
      ]
    }
  4. summarize_homes_for_sale

    «Og hvor stor andel ble solgt?» — the same two Junes, the same stock, split by how each home left it. One pass, so the four counts add up.

    {
      "name": "summarize_homes_for_sale",
      "arguments": {
        "municipality_name": "Oslo",
        "outcome": "all",
        "groupBy": "none",
        "format": "data",
        "windows": [
          {
            "label": "juni 2025",
            "from": "2025-06-01",
            "to": "2025-06-30"
          },
          {
            "label": "juni 2026",
            "from": "2026-06-01",
            "to": "2026-06-30"
          }
        ]
      }
    }
    Returned 2 derived row(s) across 2 window(s) — aggregated statistics (no raw documents).
    
    {
      "batch": { "tool": "summarize_homes_for_sale", "window_count": 2, "note": "… `results[i]` belongs to `windows[i]` …" },
      "windows": [
        {
          "label": "juni 2025", "status": "ok", "hint": "added_date_-1",
          "homes_on_market": 4768,
          "num_sold": 2406, "sold_share": 0.5046,
          "num_withdrawn": 157, "withdrawn_share": 0.0329,
          "num_still_on_market": 2205, "still_on_market_share": 0.4625
        },
        {
          "label": "juni 2026", "status": "ok", "hint": "added_date_-1",
          "homes_on_market": 5507,
          "num_sold": 2322, "sold_share": 0.4216,
          "num_withdrawn": 249, "withdrawn_share": 0.0452,
          "num_still_on_market": 2936, "still_on_market_share": 0.5331
        }
      ],
      "results": [
        {
          "status": "ok",
          "source": "Solgt.no — resale listings …. OUTCOME SPLIT: the homes on the market in the period, by how each left it — sold, withdrawn, or still for sale.",
          "scope": { "on_market_in": "within window", "field": "added_date + sold_date/inactive_date", "from": "2025-06-01T00:00:00.000Z", "to": "2025-06-30T23:59:59.999Z", "lookback_months": 24 },
          "outcome": "all",
          "groupBy": "none",
          "definitions": {
            "sold": "SOLD = the broker marked the ad sold (sold: true) — the brokered sale, weeks before it is tinglyst; counted when the home left the market, normally sold_date.",
            "withdrawn": "WITHDRAWN = taken off the market with no sale recorded (inactive: true, sold null), dated by inactive_date.",
            "still_on_market": "STILL ON MARKET = on the market in the period and neither sold nor withdrawn by the end of it."
          },
          "overall": { "homes_on_market": 4768, "num_sold": 2406, "sold_share": 0.5046, "num_withdrawn": 157, "withdrawn_share": 0.0329, "num_still_on_market": 2205, "still_on_market_share": 0.4625 },
          "metrics_legend": { … every key above, and why num_withdrawn here and in outcome "withdrawn" can differ by a handful … }
        },
        { … juni 2026, same shape … }
      ]
    }

The point Both the number and the share are up: 158 withdrawals out of 4 768 homes on the market in June 2025, 252 out of 5 507 in June 2026 — 3,3 % against 4,6 %. The month series says the same thing as a trend: 2,2 % of Oslo's inventory was pulled in January and 6,7 % in August, and the share rises alongside the count rather than merely tracking a bigger market. Read withdrawn_share; dividing the two figures by hand is how a rounded percentage becomes a headline. homes_on_market covers exactly the days the count covers, so a period starting mid-month never puts a few days of withdrawals over a whole month of inventory. Its one gap is the stock's 24-month look-back — a home first advertised longer ago than that and withdrawn inside the period is in the count but not the denominator, which here was 3 of the 252. And a SOLD home is never in either figure: an inactive row that also carries a sale belongs to summarize_sold_homes. The second call is the same question asked for rows — Vargveien 1F lay out 1 537 days and had its price cut eight times before it was pulled. June reads 252 in the first call and 251 in the third, and that is not a discrepancy to chase: a window is bounded by the dates you gave in UTC, while a month bucket is a calendar month in Europe/Oslo, so one withdrawal in the last two hours of 30 June belongs to July's bucket. Every month series on this surface behaves that way — except the split's, which draws its buckets in UTC like the window itself. A period longer than twelve months is more than one window — for two years of monthly withdrawals, ask twice, or pass the years as windows. The fourth call puts the withdrawal beside the sale: half of June 2025's stock sold in the month and 42 % of June 2026's, while the withdrawn share went from 3,3 % to 4,5 % — so more homes are being pulled AND fewer are selling, and the rest is simply still out there. Its 249 withdrawals against the 252 the first call counts for the same June are the look-back at work, not a disagreement: the split counts every figure off the same homes so the three add up, and three of June's withdrawals were first advertised more than two years earlier. Read the definitions the answer carries rather than guessing which flag a word stands for: a sale here is the broker marking the ad sold, weeks before tinglysing.

One company in depth

The orgnr comes out of resolve_company_group (or any next.get_company hop). One call returns the company card, the latest filing, the owner per register year, the board, and the subsidiaries to walk next.

  1. get_company

    Copied from resolve_company_group's answer for "Heimstaden" — never assembled by hand.

    {
      "name": "get_company",
      "arguments": {
        "orgnr": "819330492"
      }
    }
    HEIMSTADEN BOSTAD INVEST 10 AS (819330492) · regnskap: levert · 6 aksjonærår · 2 rollegruppe(r) · 20 datterselskap(er) · eier 2213 eiendom(mer).
    
    {
      "status": "ok",
      "shown": 1,
      "total": 1,
      "next": {
        "get_company": [{ "orgnr": "989079638" }, { "orgnr": "916349114" }, … , { "orgnr": "914205816" }],
        "get_owner_portfolio": { "orgnr": "819330492" }
      },
      "selskap": {
        "orgnr": "819330492",
        "navn": "HEIMSTADEN BOSTAD INVEST 10 AS",
        "organisasjonsform": { "kode": "AS", "beskrivelse": "Aksjeselskap" },
        "naeringskoder": [{ "kode": "68.200", "beskrivelse": "Utleie av egen eller leid fast eiendom" }],
        "adresse": { "gate": "Sognsveien 9C", "postnummer": "0450", "poststed": "OSLO", "kommune": "OSLO", "kommunenummer": "0301" },
        "stiftelsesdato": "2017-05-30",
        "kapital": { "belop": 80000, "antall_aksjer": 100, "type": "Aksjekapital", "valuta": "NOK" },
        "status": { "aktiv": true, "konkurs": false, "under_avvikling": false, "under_tvangsavvikling": false },
        "konsern": { "topp_orgnr": null, "topp_navn": "HEIMSTADEN BOSTAD AB", "topp_andel": 100, "topp_er_utenlandsk": true },
        "eiendommer": { "eier_antall": 2213, "beliggenhet_unitkeys": ["0301-47-340-0-0"] }
      },
      "regnskap": {
        "status": "levert",
        "siste_aar": 2025,
        "regnskap": [{
          "aar": 2025,
          "omsetning": 447094148,
          "driftsresultat": 278332852,
          "aarsresultat": -485807758,
          "egenkapital": 7005243533,
          "sum_eiendeler": 20450776188,
          "sum_gjeld": 13445532656,
          "egenkapitalandel_prosent": 34.3,
          "morselskap": true
        }]
      },
      "aksjonaerer": [
        {
          "register_aar": 2025,
          "total_shares": 100,
          "total_shareholders": 1,
          "shareholders": [{
            "navn": "HEIMSTADEN BOSTAD AB",
            "holder_form": "utenlandsk_selskap",
            "orgnr": null,
            "country_code": "SE",
            "share_count": 100,
            "ownership_percentage": 100
          }]
        },
        { "register_aar": 2024, … the same sole owner, each year back to 2020 … }
      ],
      "roller": [
        {
          "gruppe": "Styre",
          "roller": [
            { "rolle": "Styrets leder", "person": { "navn": "PAUL STEFANO SPINA", "fodselsaar": 1987 } },
            { "rolle": "Styremedlem", "person": { "navn": "MARIANNE FRØNSDAL", "fodselsaar": 1976 } },
            { "rolle": "Styremedlem", "person": { "navn": "THOMAS ALEXANDER HANSEN", "fodselsaar": 1975 } }
          ]
        },
        { "gruppe": "Revisor", "roller": [{ "rolle": "Revisor", "enhet": { "orgnr": "976389387", "navn": "ERNST & YOUNG AS" } }] }
      ],
      "datterselskaper": {
        "shown": 20,
        "total": 20,
        "selskaper": [
          { "orgnr": "989079638", "navn": "ALEXANDRAGÅRDEN AS", "ownership_percentage": 100 },
          { "orgnr": "916349114", "navn": "AMMERUDVEIEN 19-25 AS", "ownership_percentage": 100 },
          … 18 more, every one held 100 % …
        ]
      }
    }

The point The source typed the Swedish parent as a person; holder_form: "utenlandsk_selskap" is the re-derived answer, and register_aar dates each ownership picture. The filing is the latest year only — no trend lives here — and next.get_company already carries the subsidiaries, ready to pass through unchanged.

How far is it, really, to the T-bane and the nearest school

The key names one apartment in Akersgata; the question is about what lies around it. Two of the three distances per place are routed, and the first row shows why that matters: Stortinget is 66 m away as the crow flies and 334 m on foot, because the entrance is on the other side of the block.

  1. get_nearby_places

    The seksjon key, straight out of resolve_property.next. types is narrowed because the question is about two things, not seventeen.

    {
      "name": "get_nearby_places",
      "arguments": {
        "unitkeys": ["0301-208-1-0-4"],
        "types": ["metro", "school"]
      }
    }
    Returned 6 place(s) across 2 type(s) for 1 propert(y/ies); 0 without an enrichment row.
    
    {
      "status": "ok",
      "shown": 6,
      "total": 391,
      "next": {
        "get_property_facts": { "unitkeys": ["0301-208-1-0-4"] },
        "get_owners":         { "unitkeys": ["0301-208-1-0-4"] }
      },
      "notes": [
        "KUN DE TRE NÆRMESTE PER TYPE er lagret. `found` sier hvor mange som finnes innenfor `radius_m` og `withheld` hvor mange som ikke er med. …",
        "`air_m` er luftlinje. `walk` og `drive` er RUTET langs vei og gangnett, og det er dem spørsmålet «hvor langt er det til X» handler om. …",
        "Bare luftlinje, gange og bil finnes. Det er INGEN kollektivreisetid og ingen sykkeltid her …",
        …
      ],
      "types_requested": ["metro", "school"],
      "keys_not_enriched": [],
      "properties": [
        {
          "new_unitkey": "0301-208-1-0-4",
          "enriched": true,
          "origin": { "lat": 59.914228, "lng": 10.743043 },
          "updated_at": "2026-06-10T00:40:37.300Z",
          "categories": {
            "transport": {
              "metro": {
                "searched": true, "radius_m": 10000, "found": 267, "shown": 3, "withheld": 264,
                "places": [
                  { "name": "Stortinget",       "air_m": 66,  "walk": { "distance_m": 334, "minutes": 4 }, "drive": { "distance_m": 65,   "minutes": 1 }, "walk_detour_ratio": 5.1, "attributes": { "network": "Ruter", "operator": "Sporveien T-banen", … } },
                  { "name": "Jernbanetorget",   "air_m": 531, "walk": { "distance_m": 781, "minutes": 9 }, "drive": { "distance_m": 2755, "minutes": 6 }, "walk_detour_ratio": 1.5, … },
                  { "name": "Nationaltheatret", "air_m": 638, "walk": { "distance_m": 755, "minutes": 9 }, "drive": { "distance_m": 773,  "minutes": 2 }, "walk_detour_ratio": 1.2, … }
                ]
              }
            },
            "education": {
              "school": {
                "searched": true, "radius_m": 5000, "found": 124, "shown": 3, "withheld": 121,
                "places": [
                  { "name": "Prosjektskolen",              "air_m": 316, "walk": { "distance_m": 365, "minutes": 4 }, "attributes": { "amenity": "school", "grades": "11-13", "isced:level": "3", "operator:type": "private" }, … },
                  { "name": "Studieforbundet AOF Norge",   "air_m": 398, "walk": { "distance_m": 577, "minutes": 7 }, "attributes": { "amenity": "school" }, … },
                  { "name": "Otto Treider private gymnas", "air_m": 425, "walk": { "distance_m": 484, "minutes": 6 }, "attributes": { "amenity": "school", "grades": "11-13", "isced:level": "3", … }, … }
                ]
              }
            }
          }
        }
      ]
    }

The point Quote 334 m on foot to Stortinget, not 66 m. And the three nearest schools are all videregående (grades: 11-13) — that answers «er det en barneskole i nærheten?» with «ingen av de tre nærmeste er en barneskole», never with «det finnes ingen barneskole».

From a landlord's name to the whole konsern

Heimstaden owns over three thousand homes in Norway and HEIMSTADEN AS owns none of them. The portfolio sits in 31 companies, most of whose names — AMMERUDVEIEN 19-25 AS, SANNERTERRASSEN AS — carry no trace of the group; they are found through the registered group parent, and the group parent itself is Swedish.

  1. resolve_company_group

    The name as the user wrote it. resolve_owner would have answered a different question — which single party is called this — and reported a company that owns nothing.

    {
      "name": "resolve_company_group",
      "arguments": {
        "name": "Heimstaden"
      }
    }
    31 selskap i gruppen "Heimstaden" · 22 eier eiendom · 3097 eiendom(mer) totalt (26 matrikkelenheter + 3071 seksjoner/andeler).
    Levers: navn 14 · konsern 23 · matching=exact
    
    {
      "status": "ok",
      "shown": 31,
      "total": 31,
      "next": {
        "get_company":         [ { "orgnr": "819330492" }, { "orgnr": "914205816" }, … ],
        "get_owner_portfolio": [ { "orgnr": "819330492" }, { "orgnr": "914205816" }, … ]
      },
      "notes": [
        "Spelling was matched exactly (the fuzzy name index is not live on this cluster), so an empty or short result may be a misspelling rather than a missing group …",
        "Most of this group was found through `_konsern.topp_navn`, not through the company name: these are single-purpose companies whose own names carry no trace of the group. Naming only the ones whose name matches would understate the portfolio.",
        "Group parent(s) on record: HEIMSTADEN BOSTAD AB. A NULL `konsern_topp_orgnr` means the parent is FOREIGN and has no Norwegian organisasjonsnummer — normal for this class of owner, not a data gap."
      ],
      "query": { "name": "Heimstaden", "normalized": "HEIMSTADEN", "matching": "exact" },
      "group": {
        "companies_matched": 31,
        "via_navn": 14,
        "via_konsern": 23,
        "konsern_topp": ["HEIMSTADEN BOSTAD AB"],
        "parcels": 26,
        "sub_units": 3071,
        "total": 3097,
        "holding_companies": 22
      },
      "companies": [
        { "orgnr": "819330492", "navn": "HEIMSTADEN BOSTAD INVEST 10 AS", "konsern_topp": "HEIMSTADEN BOSTAD AB", "konsern_topp_orgnr": null, "via": "navn+konsern", "holdings": { "parcels": 1, "sub_units": 2056, "total": 2057, "kommuner": [{ "nummer": "0301", "navn": "OSLO" }] }, "next": { "get_company": { "orgnr": "819330492" }, "get_owner_portfolio": { "orgnr": "819330492" } } },
        { "orgnr": "914205816", "navn": "HEIMSTADEN PROPERTY 2 AS",       "via": "navn+konsern", "holdings": { "parcels": 0, "sub_units": 450, "total": 450, … }, … },
        { "orgnr": "916349114", "navn": "AMMERUDVEIEN 19-25 AS",          "via": "konsern",      "holdings": { "parcels": 1, "sub_units": 35,  "total": 36,  … }, … },
        { "orgnr": "989641522", "navn": "SANNERTERRASSEN AS",             "via": "konsern",      "holdings": { "parcels": 0, "sub_units": 10,  "total": 10,  … }, … },
        { "orgnr": "934631005", "navn": "HEIMSTADEN NORWAY AS",           "via": "navn",         "holdings": { "parcels": 0, "sub_units": 0,   "total": 0,   "kommuner": [] }, "next": { "get_company": { "orgnr": "934631005" } } },
        …
      ]
    }
  2. resolve_company_group

    The properties themselves, in one call: a page of the group's Oslo holdings with the holding company on every row. Past one page, mode: "dataset" stores the whole list as a file.

    {
      "name": "resolve_company_group",
      "arguments": {
        "name": "Olav Thon",
        "mode": "rows",
        "kommune": "Oslo"
      }
    }
    391 eiendom(mer) i gruppen "Olav Thon" i OSLO · 61 selskap, 15 eier eiendom (175 matrikkelenheter + 216 seksjoner/andeler); showing 25 on page 0 — more available.
    
    {
      "status": "ok",
      "shown": 25,
      "total": 391,
      "mode": "rows",
      "page": 0,
      "page_size": 25,
      "has_more": true,
      "group": { "companies_matched": 61, "via_navn": 7, "via_konsern": 54, "parcels": 175, "sub_units": 216, "total": 391, "holding_companies": 15 },
      "properties": [
        {
          "new_unitkey": "0301-207-88-0-0",
          "address": "Karl Johans gate 10, 0154 OSLO",
          "kommunenummer": "0301",
          "stake": { "prosent": 100, "type": "Eiendomsrett" },
          "owned_via": "parcel",
          "eier": { "orgnr": "921487541", "navn": "AUSTLID EIENDOM AS" }
        },
        …
      ]
    }

The point Report 3 097 properties across 22 holding companies, not the 0 that HEIMSTADEN AS holds. konsern_topp_orgnr: null is the Swedish parent, not missing data. Drill into any company by copying its next.get_company — never by typing an organisasjonsnummer.

When it says no

Coming up short is not one answer, and the difference between them is the difference between a hedge and a wrong answer.

A fødselsnummer is refused, and not echoed

Sent as a name, to the one tool that looks up people. The eleven digits below fail the fødselsnummer check digits, so they are nobody's — and note what the answer does not contain.

  1. resolve_owner

    {
      "name": "resolve_owner",
      "arguments": {
        "name": "26045200190"
      }
    }
    resolve_owner: that is an 11-digit fødselsnummer, not a name, and this tool will not accept one. A person is looked up by NAME here and addressed by `grunnbok_id` afterwards; their national ID is not an input to anything, is never returned, and must never be asked of a user or accepted if offered. Pass the person's name instead.

The point The number does not appear in the refusal. It is stripped of separators before it is measured, so 260452-00190 is caught by the same guard rather than falling through to a message that would quote it — and it therefore reaches neither the model's context nor the stored audit row.

A municipality we do not hold

The address resolved fine. Saksinnsyn simply does not cover Ålesund, so nothing was looked up.

  1. get_innsyn_cases

    {
      "name": "get_innsyn_cases",
      "arguments": {
        "address": "Keiser Wilhelms gate 11",
        "kommune": "Ålesund"
      }
    }
    No saksinnsyn coverage for the requested property. Solgt holds 61 kommuner; this one is not among them, so no query ran.
    THIS IS NOT AN EMPTY RESULT — nothing was looked up, so this says nothing about whether the property has cases.
    Point the user at `where_to_check`: Søk i Ålesund kommunes egen postliste.
    
    {
      "status": "kommune_not_covered",
      "shown": 0,
      "total": null,
      "next": {},
      "kommune_coverage": {
        "covered": [],
        "not_covered": [ { "unitkey": "1508-201-789-0-0", "kommune": "ÅLESUND" } ],
        "kommuner_in_corpus": 61
      },
      "where_to_check": {
        "kommune": "Ålesund",
        "url": "https://www.google.com/search?q=%C3%85lesund%20kommune%20postliste%20innsyn",
        "label": "Søk i Ålesund kommunes egen postliste"
      },
      "resolved_from_address": {
        "query": "Keiser Wilhelms gate 11",
        "units_matched": 1,
        "matrikkelenheter": ["1508-201-789-0-0"]
      }
    }

The point total: null, not 0. Nothing was counted because nothing was asked, and the answer carries the municipality's own postliste as the place to look instead.

A key that cannot answer the question

A borettslagsandel, asked for municipal cases. The property is in Oslo — our largest corpus — so this is emphatically not a coverage answer.

  1. get_innsyn_cases

    {
      "name": "get_innsyn_cases",
      "arguments": {
        "unitkeys": ["989760890-13"],
        "level": "unit"
      }
    }
    This key names no matrikkelenhet, so saksinnsyn could not be asked FROM IT. This is NOT a coverage answer — we may well hold the kommune. Re-resolve the key with resolve_property and pass its `next.get_innsyn_cases`, or ask by address.
    THIS IS NOT AN EMPTY RESULT — nothing was looked up, so this says nothing about whether the property has cases.
    
    {
      "status": "wrong_level",
      "shown": 0,
      "total": null,
      "next": {},
      "budget": { "db_ms": 0, "hops": 0, "rows_cap": 100 },
      "notes": [
        "989760890-13 — a borettslagsandel key names no matrikkelenhet, and Innsyn files every case against one. So nothing could be looked up FROM THIS KEY. This says nothing about coverage and nothing about the property: call resolve_property with this key and use its `next.get_innsyn_cases` — that carries the matrikkelenhet — or ask by address."
      ],
      "kommune_coverage": { "covered": [], "not_covered": [], "kommuner_in_corpus": 61 }
    }

The point db_ms: 0, hops: 0 — the database was never touched. The fix is one call: resolve the key, then pass next.get_innsyn_cases on, because that is what carries the matrikkelenhet the andel stands on.

An empty answer that is a finding

The company holds seven properties and has never given up one. empty here is the answer, not the absence of one.

  1. get_owner_history

    {
      "name": "get_owner_history",
      "arguments": {
        "orgnr": "985836809"
      }
    }
    AMT EIENDOM AS has no registered disposal of any property — they have never given up a holding recorded here. That is a FINDING, not a failed lookup.
    `holding_status` is the party's standing today — `sold` means they are out, `still_owner` means they are not. …
    
    {
      "status": "empty",
      "shown": 0,
      "total": 0,
      "sections": {
        "owner":            { "status": "ok",    "data": { "grunnbok_id": 9631997 } },
        "disposals":        { "status": "empty", "reason": "this party has no registered disposal of any property matching the filters" },
        "current_holdings": { "status": "ok",    "data": { "properties": 7 } }
      },
      "notes": [
        "This party has never given up a holding recorded here. …"
      ],
      "owner": { "grunnbok_id": 9631997, "navn": "AMT EIENDOM AS", "org_number": "985836809" },
      "properties": []
    }

The point Three sections, three different statuses in one answer. current_holdings confirms the party exists and holds seven properties, which is what turns the empty disposals section from an unexplained blank into a statement.

An empty owner list that means the opposite

The same building as above, asked at the matrikkelenhet instead of at a seksjon. It has no owner — and reporting that as "nobody owns it" would be wrong twenty times over.

  1. get_owners

    {
      "name": "get_owners",
      "arguments": {
        "unitkeys": ["0301-208-1-0-0"]
      }
    }
    0 registered owner(s) across 1 of 1 requested property.
    `owners_read_from` names the document each answer came off — for a seksjon that is the parcel, whose OWN owner is somebody else.
    
    {
      "status": "empty",
      "shown": 0,
      "total": 1,
      "notes": [
        "0301-208-1-0-0 is a sameie matrikkelenhet with 20 sub-units and NO owner of its own — it is owned one level down, seksjon by seksjon. …"
      ],
      "properties": [
        {
          "requested": "0301-208-1-0-0",
          "level": "parcel",
          "type": "Matrikkelenhet",
          "address": "Akersgata 32, 0180 OSLO",
          "owners_status": "owned_at_unit_level",
          "owners": [],
          "totals": { "antall_eiere": 0, "antall_selskaper": 0, "antall_personer": 0 },
          "owned_units": {
            "antall": 20,
            "unitkeys": ["0301-208-1-0-1", "0301-208-1-0-2", … ],
            "truncated": false
          }
        }
      ]
    }

The point status: "empty" and owners_status: "owned_at_unit_level" are two different statements, and only the second one is the answer. A sameie is owned seksjon by seksjon; owned_units.unitkeys is the list to ask about instead, and it is in the payload rather than in a note you have to act on.

A filter value we do not recognise

Bydeler are city districts, not neighbourhoods, and the spelling is the register's. A value that misses used to come back as a clean zero — a real number for a question nobody answered.

  1. summarize_sold_homes

    {
      "name": "summarize_sold_homes",
      "arguments": {
        "kommune_name": "Oslo",
        "bydel_navn": "Grunerlokka",
        "lastMonths": 3,
        "groupBy": "none",
        "format": "data"
      }
    }
    Returned 0 derived row(s) — aggregated statistics (no raw documents).
    
    {
      "status": "not_found",
      "unresolved_filters": [
        {
          "param": "bydel_navn",
          "value": "Grunerlokka",
          "reason": "'Grunerlokka' is not a bydel of OSLO. Bydeler are city-DISTRICTS, not neighbourhoods — map sub-areas to their district (e.g. Adamstuen → St.Hanshaugen). Valid OSLO bydeler: Alna, Bjerke, Frogner, Gamle Oslo, Grorud, Grünerløkka, Marka, Nordre Aker, Nordstrand, Sagene, Sentrum, St.Hanshaugen, Stovner, Søndre Nordstrand, Ullern, Vestre Aker, Østensjø."
        }
      ],
      "filters": { "kommune_name": "Oslo", "bydel_navn": "Grunerlokka" },
      "groupBy": "none"
    }

The point status: "not_found" with the filter that missed and every value that would have worked. Zero sales and a filter that matched nothing are different answers, and the market tools now say which one you got — so read status before you read num_sales.

A key with three segments is refused, not guessed

0301-208-1 looks like the start of a real key and is a plausible thing to assemble by hand. The surface will not fill in the missing two segments for you.

  1. resolve_property

    {
      "name": "resolve_property",
      "arguments": {
        "new_unitkey": "0301-208-1"
      }
    }
    resolve_property: "0301-208-1" is not a new_unitkey. Two shapes are valid: knr-gnr-bnr-fnr-snr (5 segments, e.g. 0301-211-69-0-1) and <borettslagnummer>-<andelsnummer> (2 segments, e.g. 989760890-13). For loose matrikkel parts pass { matrikkel: { knr, gnr, bnr } }; for anything a human typed pass { address }.

The point The refusal names both valid shapes and both alternative doors, so it is a correction rather than a dead end. This is why keys travel through next instead of being assembled: a key you built is a key nobody checked.

An address that matches nothing

The street exists in the portfolio above, but not with this spelling in this municipality. The tool says so, and says what not to do about it.

  1. resolve_property

    {
      "name": "resolve_property",
      "arguments": {
        "address": "Bukteløkka 31",
        "kommune": "Halden"
      }
    }
    Resolved 0 of 1 requested property via address (index `bruksenheter.adresse_1 + bruksenhet.adresse_1`).
    "Bukteløkka 31" matched no unit. …
    
    {
      "status": "not_found",
      "shown": 0,
      "total": 1,
      "next": {},
      "address_match": {
        "query": "Bukteløkka 31",
        "street_forms": ["bukteløkka"],
        "husnummer": "31",
        "bokstav": null,
        "kommunenummer": ["3101", "3001"],
        "patterns_tried": ["^Bukteløkka 31\\s?[A-Za-zÆØÅæøå]?$", "^BUKTELØKKA 31\\s?[A-Za-zÆØÅæøå]?$"],
        "units_matched": 0,
        "entrances": [],
        "other_entrances_at_this_number": [],
        "utgaatt_matches": 0
      }
    }

The point next is empty and no key is offered. The honest next move is to ask the user for the address again — sweeping the area with a market search and picking something that looks close is how a confident answer about the wrong property gets made.

A country's worth of rows, refused — and the route that carries it

The same question as the national count, asked as rows instead. One page of 25 is not the country, and the tool will not let paging imply otherwise; the refusal names the route that does carry the complete list — and, for the scope it does not have, it hands the choice back to the person who asked.

  1. search_commercial_properties

    {
      "name": "search_commercial_properties",
      "arguments": {
        "naeringskode": "47.11",
        "mode": "rows"
      }
    }
    search_commercial_properties: a national `rows` answer is ~4 800 properties — too big to read in one response. The national routes need no scope: mode:"dataset" stores the COMPLETE set (you receive a summary envelope; the app shows the rows), and mode:"count" gives the totals and breakdowns. Without a dataset surface the complete list is all 15 fylker walked in turn, each call bounded and its `total` exact. Paging rows for one place instead would need a `kommune` or a `fylke`. A route above that answers the question as it stands — a count, a distribution, a set that fits — is not a narrowing: take it. The rest ARE narrowings, and which to take is the user's decision, not yours: put them to the user as a payload spells them — never a code or a count written from memory, never two of them added together — and do not run one of them yourself in this turn.

The point A national answer is counts and a distribution, or a stored dataset — never a page of rows pretending to be the market. mode: "dataset" is the route that actually carries the complete list: the full row set is stored for the calling application to render, and only a summary envelope — columns, counts, a five-row preview, caveats — comes back through the model, so nothing gets retyped and nothing gets truncated. mode: "count" answers HOW MANY. A county at a time is a third route, exact total per county across the 15 fylker, for a caller with no dataset surface — but a county is a scope, and the refusal deliberately stops short of choosing one: the assistant is expected to put that choice to the person who asked rather than settle it quietly on Oslo. Note also what the refusal does not offer: group_by: "leieforhold" is missing on purpose, because it is the one breakdown that reads the matrikkel and the share register and so cannot be answered for the whole country; its own refusal points back at the same bounded routes rather than one that does not exist.